From 2fe802a8bdda1e628c4558f9079439893e7bd52e Mon Sep 17 00:00:00 2001 From: mpriyank Date: Tue, 8 Aug 2023 15:27:18 +0100 Subject: Refactoring Subscription Create LCM use case - Client to NCMP: CmSubscriptionNcmpInEvent - NCMP to DMI: CmSubscriptionDmiInEvent - DMI to NCMP: CmSubscriptionDmiOutEvent - NCMP to Client: CmSubscriptionNcmpOutEvent - code package changed from avcsubscription to cmsubscription - Other classes name as per the events naming above - Test classes refactored - NO LOGIC changes incorporated in this patch Issue-ID: CPS-1831 Change-Id: Id5ad5f799007deaaf6d6fc0f402c130339263d09 Signed-off-by: mpriyank --- .../ClientSubscriptionEventMapper.java | 34 ---- .../avcsubscription/ResponseTimeoutTask.java | 52 ------ .../avcsubscription/SubscriptionEventConsumer.java | 95 ---------- .../SubscriptionEventForwarder.java | 192 ------------------- .../avcsubscription/SubscriptionEventMapper.java | 52 ------ .../SubscriptionEventResponseConsumer.java | 117 ------------ .../SubscriptionEventResponseMapper.java | 55 ------ .../SubscriptionEventResponseOutcome.java | 151 --------------- .../avcsubscription/SubscriptionOutcomeMapper.java | 105 ----------- .../CmSubscriptionDmiOutEventConsumer.java | 118 ++++++++++++ ...OutEventToCmSubscriptionNcmpOutEventMapper.java | 105 +++++++++++ ...OutEventToYangModelSubscriptionEventMapper.java | 55 ++++++ .../CmSubscriptionNcmpInEventConsumer.java | 97 ++++++++++ .../CmSubscriptionNcmpInEventForwarder.java | 191 +++++++++++++++++++ .../CmSubscriptionNcmpInEventMapper.java | 52 ++++++ ...cmpInEventToCmSubscriptionDmiInEventMapper.java | 35 ++++ .../CmSubscriptionNcmpOutEventPublisher.java | 153 ++++++++++++++++ .../events/cmsubscription/ResponseTimeoutTask.java | 52 ++++++ .../impl/utils/CmSubscriptionEventCloudMapper.java | 86 +++++++++ .../impl/utils/SubscriptionEventCloudMapper.java | 90 --------- .../SubscriptionEventResponseCloudMapper.java | 18 +- .../impl/utils/SubscriptionOutcomeCloudMapper.java | 12 +- .../ClientSubscriptionEventMapperSpec.groovy | 60 ------ .../SubscriptionEventConsumerSpec.groovy | 108 ----------- .../SubscriptionEventForwarderSpec.groovy | 203 -------------------- .../SubscriptionEventMapperSpec.groovy | 79 -------- .../SubscriptionEventResponseConsumerSpec.groovy | 142 -------------- .../SubscriptionEventResponseMapperSpec.groovy | 60 ------ .../SubscriptionEventResponseOutcomeSpec.groovy | 124 ------------- .../SubscriptionOutcomeMapperSpec.groovy | 87 --------- ...lientCmSubscriptionNcmpInEventMapperSpec.groovy | 60 ++++++ .../CmSubscriptionDmiOutEventConsumerSpec.groovy | 142 ++++++++++++++ ...ntToCmSubscriptionNcmpOutEventMapperSpec.groovy | 87 +++++++++ ...ntToYangModelSubscriptionEventMapperSpec.groovy | 60 ++++++ .../CmSubscriptionNcmpInEventConsumerSpec.groovy | 108 +++++++++++ .../CmSubscriptionNcmpInEventForwarderSpec.groovy | 204 +++++++++++++++++++++ .../CmSubscriptionNcmpInEventMapperSpec.groovy | 78 ++++++++ .../CmSubscriptionNcmpOutEventPublisherSpec.groovy | 124 +++++++++++++ .../CmSubscriptionEventCloudMapperSpec.groovy | 115 ++++++++++++ .../utils/SubscriptionEventCloudMapperSpec.groovy | 114 ------------ ...SubscriptionEventResponseCloudMapperSpec.groovy | 10 +- .../SubscriptionOutcomeCloudMapperSpec.groovy | 12 +- .../resources/avcSubscriptionCreationEvent.json | 22 --- .../avcSubscriptionCreationEventNcmpVersion.json | 31 ---- .../resources/avcSubscriptionEventResponse.json | 29 --- .../resources/avcSubscriptionOutcomeEvent.json | 24 --- .../resources/avcSubscriptionOutcomeEvent2.json | 20 -- .../test/resources/cmSubscriptionDmiInEvent.json | 31 ++++ .../test/resources/cmSubscriptionDmiOutEvent.json | 29 +++ .../test/resources/cmSubscriptionNcmpInEvent.json | 22 +++ .../test/resources/cmSubscriptionNcmpOutEvent.json | 24 +++ .../resources/cmSubscriptionNcmpOutEvent2.json | 20 ++ 52 files changed, 2074 insertions(+), 2072 deletions(-) delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapper.java delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/resources/avcSubscriptionCreationEvent.json delete mode 100644 cps-ncmp-service/src/test/resources/avcSubscriptionCreationEventNcmpVersion.json delete mode 100644 cps-ncmp-service/src/test/resources/avcSubscriptionEventResponse.json delete mode 100644 cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent.json delete mode 100644 cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent2.json create mode 100644 cps-ncmp-service/src/test/resources/cmSubscriptionDmiInEvent.json create mode 100644 cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json create mode 100644 cps-ncmp-service/src/test/resources/cmSubscriptionNcmpInEvent.json create mode 100644 cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json create mode 100644 cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent2.json (limited to 'cps-ncmp-service') diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapper.java deleted file mode 100644 index 59b1d09c7..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapper.java +++ /dev/null @@ -1,34 +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.events.avcsubscription; - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent; - -@Mapper(componentModel = "spring") -public interface ClientSubscriptionEventMapper { - - @Mapping(target = "data.predicates.targets", ignore = true) - org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent toNcmpSubscriptionEvent( - SubscriptionEvent subscriptionEvent); - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java deleted file mode 100644 index e3f529787..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java +++ /dev/null @@ -1,52 +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.events.avcsubscription; - -import com.hazelcast.map.IMap; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; - -@Slf4j -@RequiredArgsConstructor -public class ResponseTimeoutTask implements Runnable { - - private final IMap> forwardedSubscriptionEventCache; - private final SubscriptionEventResponseOutcome subscriptionEventResponseOutcome; - private final SubscriptionEventResponse subscriptionEventResponse; - - @Override - public void run() { - generateTimeoutResponse(); - } - - private void generateTimeoutResponse() { - final String subscriptionClientId = subscriptionEventResponse.getData().getClientId(); - final String subscriptionName = subscriptionEventResponse.getData().getSubscriptionName(); - final String subscriptionEventId = subscriptionClientId + subscriptionName; - if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { - subscriptionEventResponseOutcome.sendResponse(subscriptionEventResponse, - "subscriptionCreatedStatus"); - forwardedSubscriptionEventCache.remove(subscriptionEventId); - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumer.java deleted file mode 100644 index 8dfdc3cd4..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumer.java +++ /dev/null @@ -1,95 +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.events.avcsubscription; - -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 io.cloudevents.CloudEvent; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventCloudMapper; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - - -@Component -@Slf4j -@RequiredArgsConstructor -public class SubscriptionEventConsumer { - - private final SubscriptionEventForwarder subscriptionEventForwarder; - private final SubscriptionEventMapper subscriptionEventMapper; - private final SubscriptionPersistence subscriptionPersistence; - private final SubscriptionEventCloudMapper subscriptionEventCloudMapper; - - @Value("${notification.enabled:true}") - private boolean notificationFeatureEnabled; - - @Value("${ncmp.model-loader.subscription:false}") - private boolean subscriptionModelLoaderEnabled; - - /** - * Consume the specified event. - * - * @param subscriptionEventConsumerRecord the event to be consumed - */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-topic}", - containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void consumeSubscriptionEvent(final ConsumerRecord subscriptionEventConsumerRecord) { - final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value(); - final String eventType = subscriptionEventConsumerRecord.value().getType(); - final SubscriptionEvent subscriptionEvent = subscriptionEventCloudMapper.toSubscriptionEvent(cloudEvent); - final String eventDatastore = subscriptionEvent.getData().getPredicates().getDatastore(); - if (!eventDatastore.equals(PASSTHROUGH_RUNNING.getDatastoreName()) - || eventDatastore.equals(PASSTHROUGH_OPERATIONAL.getDatastoreName())) { - throw new UnsupportedOperationException( - "passthrough datastores are currently only supported for event subscriptions"); - } - if ("CM".equals(subscriptionEvent.getData().getDataType().getDataCategory())) { - if (subscriptionModelLoaderEnabled) { - persistSubscriptionEvent(subscriptionEvent); - } - if ("subscriptionCreated".equals(cloudEvent.getType())) { - log.info("Subscription for ClientID {} with name {} ...", - subscriptionEvent.getData().getSubscription().getClientID(), - subscriptionEvent.getData().getSubscription().getName()); - if (notificationFeatureEnabled) { - subscriptionEventForwarder.forwardCreateSubscriptionEvent(subscriptionEvent, eventType); - } - } - } else { - log.trace("Non-CM subscription event ignored"); - } - } - - private void persistSubscriptionEvent(final SubscriptionEvent subscriptionEvent) { - final YangModelSubscriptionEvent yangModelSubscriptionEvent = - subscriptionEventMapper.toYangModelSubscriptionEvent(subscriptionEvent); - subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java deleted file mode 100644 index d3bfe81e8..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java +++ /dev/null @@ -1,192 +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.events.avcsubscription; - -import com.hazelcast.map.IMap; -import io.cloudevents.CloudEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; -import org.onap.cps.ncmp.api.impl.events.EventsPublisher; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; -import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer; -import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventCloudMapper; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.api.inventory.InventoryPersistence; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.Data; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.CmHandle; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - - -@Component -@Slf4j -@RequiredArgsConstructor -public class SubscriptionEventForwarder { - - private final InventoryPersistence inventoryPersistence; - private final EventsPublisher eventsPublisher; - private final IMap> forwardedSubscriptionEventCache; - private final SubscriptionEventResponseOutcome subscriptionEventResponseOutcome; - private final SubscriptionEventMapper subscriptionEventMapper; - private final SubscriptionEventCloudMapper subscriptionEventCloudMapper; - private final ClientSubscriptionEventMapper clientSubscriptionEventMapper; - private final SubscriptionPersistence subscriptionPersistence; - private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); - @Value("${app.ncmp.avc.subscription-forward-topic-prefix}") - private String dmiAvcSubscriptionTopicPrefix; - - @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms:30000}") - private int dmiResponseTimeoutInMs; - - /** - * Forward subscription event. - * - * @param subscriptionEvent the event to be forwarded - */ - public void forwardCreateSubscriptionEvent(final SubscriptionEvent subscriptionEvent, final String eventType) { - final List cmHandleTargets = subscriptionEvent.getData().getPredicates().getTargets(); - if (cmHandleTargets == null || cmHandleTargets.isEmpty() - || cmHandleTargets.stream().anyMatch(id -> (id).contains("*"))) { - throw new UnsupportedOperationException( - "CMHandle targets are required. \"Wildcard\" operations are not yet supported"); - } - final Collection yangModelCmHandles = - inventoryPersistence.getYangModelCmHandles(cmHandleTargets); - final Map>> dmiPropertiesPerCmHandleIdPerServiceName - = DmiServiceNameOrganizer.getDmiPropertiesPerCmHandleIdPerServiceName(yangModelCmHandles); - findDmisAndRespond(subscriptionEvent, eventType, cmHandleTargets, dmiPropertiesPerCmHandleIdPerServiceName); - } - - private void findDmisAndRespond(final SubscriptionEvent subscriptionEvent, final String eventType, - final List cmHandleTargetsAsStrings, - final Map>> - dmiPropertiesPerCmHandleIdPerServiceName) { - final SubscriptionEventResponse emptySubscriptionEventResponse = - new SubscriptionEventResponse().withData(new Data()); - emptySubscriptionEventResponse.getData().setSubscriptionName( - subscriptionEvent.getData().getSubscription().getName()); - emptySubscriptionEventResponse.getData().setClientId( - subscriptionEvent.getData().getSubscription().getClientID()); - final List cmHandlesThatExistsInDb = dmiPropertiesPerCmHandleIdPerServiceName.entrySet().stream() - .map(Map.Entry::getValue).map(Map::keySet).flatMap(Set::stream).collect(Collectors.toList()); - - final List targetCmHandlesDoesNotExistInDb = new ArrayList<>(cmHandleTargetsAsStrings); - targetCmHandlesDoesNotExistInDb.removeAll(cmHandlesThatExistsInDb); - - final Set dmisToRespond = new HashSet<>(dmiPropertiesPerCmHandleIdPerServiceName.keySet()); - - if (dmisToRespond.isEmpty() || !targetCmHandlesDoesNotExistInDb.isEmpty()) { - updatesCmHandlesToRejectedAndPersistSubscriptionEvent(subscriptionEvent, targetCmHandlesDoesNotExistInDb); - } - if (dmisToRespond.isEmpty()) { - subscriptionEventResponseOutcome.sendResponse(emptySubscriptionEventResponse, - "subscriptionCreatedStatus"); - } else { - startResponseTimeout(emptySubscriptionEventResponse, dmisToRespond); - final org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent ncmpSubscriptionEvent = - clientSubscriptionEventMapper.toNcmpSubscriptionEvent(subscriptionEvent); - forwardEventToDmis(dmiPropertiesPerCmHandleIdPerServiceName, ncmpSubscriptionEvent, eventType); - } - } - - private void startResponseTimeout(final SubscriptionEventResponse emptySubscriptionEventResponse, - final Set dmisToRespond) { - final String subscriptionClientId = emptySubscriptionEventResponse.getData().getClientId(); - final String subscriptionName = emptySubscriptionEventResponse.getData().getSubscriptionName(); - final String subscriptionEventId = subscriptionClientId + subscriptionName; - - forwardedSubscriptionEventCache.put(subscriptionEventId, dmisToRespond, - ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); - final ResponseTimeoutTask responseTimeoutTask = - new ResponseTimeoutTask(forwardedSubscriptionEventCache, subscriptionEventResponseOutcome, - emptySubscriptionEventResponse); - - executorService.schedule(responseTimeoutTask, dmiResponseTimeoutInMs, TimeUnit.MILLISECONDS); - } - - private void forwardEventToDmis(final Map>> dmiNameCmHandleMap, - final org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent - ncmpSubscriptionEvent, final String eventType) { - dmiNameCmHandleMap.forEach((dmiName, cmHandlePropertiesMap) -> { - final List cmHandleTargets = cmHandlePropertiesMap.entrySet().stream().map( - cmHandleAndProperties -> { - final CmHandle cmHandle = new CmHandle(); - cmHandle.setId(cmHandleAndProperties.getKey()); - cmHandle.setAdditionalProperties(cmHandleAndProperties.getValue()); - return cmHandle; - }).collect(Collectors.toList()); - - ncmpSubscriptionEvent.getData().getPredicates().setTargets(cmHandleTargets); - final String eventKey = createEventKey(ncmpSubscriptionEvent, dmiName); - final String dmiAvcSubscriptionTopic = dmiAvcSubscriptionTopicPrefix + dmiName; - - final CloudEvent ncmpSubscriptionCloudEvent = - subscriptionEventCloudMapper.toCloudEvent(ncmpSubscriptionEvent, eventKey, eventType); - eventsPublisher.publishCloudEvent(dmiAvcSubscriptionTopic, eventKey, ncmpSubscriptionCloudEvent); - }); - } - - private String createEventKey( - final org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent subscriptionEvent, - final String dmiName) { - return subscriptionEvent.getData().getSubscription().getClientID() - + "-" - + subscriptionEvent.getData().getSubscription().getName() - + "-" - + dmiName; - } - - private void updatesCmHandlesToRejectedAndPersistSubscriptionEvent( - final SubscriptionEvent subscriptionEvent, - final List targetCmHandlesDoesNotExistInDb) { - final YangModelSubscriptionEvent yangModelSubscriptionEvent = - subscriptionEventMapper.toYangModelSubscriptionEvent(subscriptionEvent); - yangModelSubscriptionEvent.getPredicates() - .setTargetCmHandles(findRejectedCmHandles(targetCmHandlesDoesNotExistInDb, - yangModelSubscriptionEvent)); - subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); - } - - private static List findRejectedCmHandles( - final List targetCmHandlesDoesNotExistInDb, - final YangModelSubscriptionEvent yangModelSubscriptionEvent) { - return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles().stream() - .filter(targetCmHandle -> targetCmHandlesDoesNotExistInDb.contains(targetCmHandle.getCmHandleId())) - .map(target -> new YangModelSubscriptionEvent.TargetCmHandle(target.getCmHandleId(), - SubscriptionStatus.REJECTED, "Targets not found")) - .collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapper.java deleted file mode 100644 index 35d94cc7a..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapper.java +++ /dev/null @@ -1,52 +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.events.avcsubscription; - -import java.util.List; -import java.util.stream.Collectors; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent; - -@Mapper(componentModel = "spring") -public interface SubscriptionEventMapper { - - @Mapping(source = "data.subscription.clientID", target = "clientId") - @Mapping(source = "data.subscription.name", target = "subscriptionName") - @Mapping(source = "data.predicates.targets", target = "predicates.targetCmHandles", - qualifiedByName = "mapTargetsToCmHandleTargets") - @Mapping(source = "data.predicates.datastore", target = "predicates.datastore") - YangModelSubscriptionEvent toYangModelSubscriptionEvent(SubscriptionEvent subscriptionEvent); - - /** - * Maps list of Targets to list of TargetCmHandle. - * - * @param targets list of objects - * @return TargetCmHandle list - */ - @Named("mapTargetsToCmHandleTargets") - default List mapTargetsToCmHandleTargets(List targets) { - return targets.stream().map(YangModelSubscriptionEvent.TargetCmHandle::new) - .collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java deleted file mode 100644 index b1c0a322d..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java +++ /dev/null @@ -1,117 +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.events.avcsubscription; - -import com.hazelcast.map.IMap; -import io.cloudevents.CloudEvent; -import java.util.Collection; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; -import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; -import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventResponseCloudMapper; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; -import org.onap.cps.spi.model.DataNode; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@RequiredArgsConstructor -public class SubscriptionEventResponseConsumer { - - private final IMap> forwardedSubscriptionEventCache; - private final SubscriptionPersistence subscriptionPersistence; - private final SubscriptionEventResponseMapper subscriptionEventResponseMapper; - private final SubscriptionEventResponseOutcome subscriptionEventResponseOutcome; - private final SubscriptionEventResponseCloudMapper subscriptionEventResponseCloudMapper; - - @Value("${notification.enabled:true}") - private boolean notificationFeatureEnabled; - - @Value("${ncmp.model-loader.subscription:false}") - private boolean subscriptionModelLoaderEnabled; - - /** - * Consume subscription response event. - * - * @param subscriptionEventResponseConsumerRecord the event to be consumed - */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", - containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void consumeSubscriptionEventResponse( - final ConsumerRecord subscriptionEventResponseConsumerRecord) { - final CloudEvent cloudEvent = subscriptionEventResponseConsumerRecord.value(); - final String eventType = subscriptionEventResponseConsumerRecord.value().getType(); - final SubscriptionEventResponse subscriptionEventResponse = - subscriptionEventResponseCloudMapper.toSubscriptionEventResponse(cloudEvent); - final String clientId = subscriptionEventResponse.getData().getClientId(); - log.info("subscription event response of clientId: {} is received.", clientId); - final String subscriptionName = subscriptionEventResponse.getData().getSubscriptionName(); - final String subscriptionEventId = clientId + subscriptionName; - boolean createOutcomeResponse = false; - if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { - final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); - dmiNames.remove(subscriptionEventResponse.getData().getDmiName()); - forwardedSubscriptionEventCache.put(subscriptionEventId, dmiNames, - ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); - createOutcomeResponse = forwardedSubscriptionEventCache.get(subscriptionEventId).isEmpty(); - } - if (subscriptionModelLoaderEnabled) { - updateSubscriptionEvent(subscriptionEventResponse); - } - if (createOutcomeResponse - && notificationFeatureEnabled - && hasNoPendingCmHandles(clientId, subscriptionName)) { - subscriptionEventResponseOutcome.sendResponse(subscriptionEventResponse, eventType); - forwardedSubscriptionEventCache.remove(subscriptionEventId); - } - } - - private boolean hasNoPendingCmHandles(final String clientId, final String subscriptionName) { - final Collection dataNodeSubscription = subscriptionPersistence.getCmHandlesForSubscriptionEvent( - clientId, subscriptionName); - final Map> cmHandleIdToStatusAndDetailsAsMapOriginal = - DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode(dataNodeSubscription); - for (final Map statusAndDetailsMap : cmHandleIdToStatusAndDetailsAsMapOriginal.values()) { - final String status = statusAndDetailsMap.get("status"); - if (SubscriptionStatus.PENDING.toString().equals(status)) { - return false; - } - } - return true; - } - - private void updateSubscriptionEvent(final SubscriptionEventResponse subscriptionEventResponse) { - final YangModelSubscriptionEvent yangModelSubscriptionEvent = - subscriptionEventResponseMapper - .toYangModelSubscriptionEvent(subscriptionEventResponse); - subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapper.java deleted file mode 100644 index dc122ee5d..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapper.java +++ /dev/null @@ -1,55 +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.events.avcsubscription; - -import java.util.List; -import java.util.stream.Collectors; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus; - -@Mapper(componentModel = "spring") -public interface SubscriptionEventResponseMapper { - - @Mapping(source = "data.clientId", target = "clientId") - @Mapping(source = "data.subscriptionName", target = "subscriptionName") - @Mapping(source = "data.subscriptionStatus", target = "predicates.targetCmHandles", - qualifiedByName = "mapSubscriptionStatusToCmHandleTargets") - YangModelSubscriptionEvent toYangModelSubscriptionEvent( - SubscriptionEventResponse subscriptionEventResponse); - - /** - * Maps SubscriptionStatus to list of TargetCmHandle. - * - * @param subscriptionStatus as a list - * @return TargetCmHandle list - */ - @Named("mapSubscriptionStatusToCmHandleTargets") - default List mapSubscriptionStatusToCmHandleTargets( - List subscriptionStatus) { - return subscriptionStatus.stream().map(status -> new YangModelSubscriptionEvent.TargetCmHandle(status.getId(), - org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.fromString(status.getStatus().value()), - status.getDetails())).collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java deleted file mode 100644 index 822ca5509..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java +++ /dev/null @@ -1,151 +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.events.avcsubscription; - -import io.cloudevents.CloudEvent; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.NcmpEventResponseCode; -import org.onap.cps.ncmp.api.impl.events.EventsPublisher; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; -import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; -import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.SubscriptionEventOutcome; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@RequiredArgsConstructor -public class SubscriptionEventResponseOutcome { - - private final SubscriptionPersistence subscriptionPersistence; - - private final EventsPublisher outcomeEventsPublisher; - - private final SubscriptionOutcomeMapper subscriptionOutcomeMapper; - - private final SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper; - - @Value("${app.ncmp.avc.subscription-outcome-topic:subscription-response}") - private String subscriptionOutcomeEventTopic; - - /** - * This is for construction of outcome message to be published for client apps. - * - * @param subscriptionEventResponse event produced by Dmi Plugin - */ - public void sendResponse(final SubscriptionEventResponse subscriptionEventResponse, final String eventKey) { - final SubscriptionEventOutcome subscriptionEventOutcome = - formSubscriptionOutcomeMessage(subscriptionEventResponse); - final String subscriptionClientId = subscriptionEventResponse.getData().getClientId(); - final String subscriptionName = subscriptionEventResponse.getData().getSubscriptionName(); - final String subscriptionEventId = subscriptionClientId + subscriptionName; - final CloudEvent subscriptionOutcomeCloudEvent = - subscriptionOutcomeCloudMapper.toCloudEvent(subscriptionEventOutcome, - subscriptionEventId, eventKey); - outcomeEventsPublisher.publishCloudEvent(subscriptionOutcomeEventTopic, - subscriptionEventId, subscriptionOutcomeCloudEvent); - } - - private SubscriptionEventOutcome formSubscriptionOutcomeMessage( - final SubscriptionEventResponse subscriptionEventResponse) { - final Map> cmHandleIdToStatusAndDetailsAsMap = - DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode( - subscriptionPersistence.getCmHandlesForSubscriptionEvent( - subscriptionEventResponse.getData().getClientId(), - subscriptionEventResponse.getData().getSubscriptionName())); - final List - subscriptionStatusList = mapCmHandleIdStatusDetailsMapToSubscriptionStatusList( - cmHandleIdToStatusAndDetailsAsMap); - subscriptionEventResponse.getData().setSubscriptionStatus(subscriptionStatusList); - return fromSubscriptionEventResponse(subscriptionEventResponse, - decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap)); - } - - private static List - mapCmHandleIdStatusDetailsMapToSubscriptionStatusList( - final Map> cmHandleIdToStatusAndDetailsAsMap) { - return cmHandleIdToStatusAndDetailsAsMap.entrySet() - .stream().map(entryset -> { - final org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus - subscriptionStatus = new org.onap.cps.ncmp.events.avcsubscription1_0_0 - .dmi_to_ncmp.SubscriptionStatus(); - final String cmHandleId = entryset.getKey(); - final Map statusAndDetailsMap = entryset.getValue(); - final String status = statusAndDetailsMap.get("status"); - final String details = statusAndDetailsMap.get("details"); - subscriptionStatus.setId(cmHandleId); - subscriptionStatus.setStatus( - org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp - .SubscriptionStatus.Status.fromValue(status)); - subscriptionStatus.setDetails(details); - return subscriptionStatus; - }).collect(Collectors.toList()); - } - - private NcmpEventResponseCode decideOnNcmpEventResponseCodeForSubscription( - final Map> cmHandleIdToStatusAndDetailsAsMap) { - - final boolean isAllTargetsPending = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap, - SubscriptionStatus.PENDING); - - final boolean isAllTargetsRejected = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap, - SubscriptionStatus.REJECTED); - - final boolean isAllTargetsAccepted = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap, - SubscriptionStatus.ACCEPTED); - - if (isAllTargetsAccepted) { - return NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION; - } else if (isAllTargetsRejected) { - return NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE; - } else if (isAllTargetsPending) { - return NcmpEventResponseCode.SUBSCRIPTION_PENDING; - } else { - return NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION; - } - } - - private boolean isAllTargetCmHandleStatusMatch( - final Map> cmHandleIdToStatusAndDetailsAsMap, - final SubscriptionStatus subscriptionStatus) { - return cmHandleIdToStatusAndDetailsAsMap.values().stream() - .allMatch(entryset -> entryset.containsValue(subscriptionStatus.toString())); - } - - private SubscriptionEventOutcome fromSubscriptionEventResponse( - final SubscriptionEventResponse subscriptionEventResponse, - final NcmpEventResponseCode ncmpEventResponseCode) { - - final SubscriptionEventOutcome subscriptionEventOutcome = - subscriptionOutcomeMapper.toSubscriptionEventOutcome(subscriptionEventResponse); - subscriptionEventOutcome.getData().setStatusCode(Integer.parseInt(ncmpEventResponseCode.getStatusCode())); - subscriptionEventOutcome.getData().setStatusMessage(ncmpEventResponseCode.getStatusMessage()); - - return subscriptionEventOutcome; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java deleted file mode 100644 index 7803b982f..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java +++ /dev/null @@ -1,105 +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.events.avcsubscription; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.AdditionalInfo; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.AdditionalInfoDetail; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.SubscriptionEventOutcome; -import org.onap.cps.spi.exceptions.DataValidationException; - -@Mapper(componentModel = "spring") -public interface SubscriptionOutcomeMapper { - - @Mapping(source = "data.subscriptionStatus", target = "data.additionalInfo", - qualifiedByName = "mapListOfSubscriptionStatusToAdditionalInfo") - SubscriptionEventOutcome toSubscriptionEventOutcome(SubscriptionEventResponse subscriptionEventResponse); - - /** - * Maps list of SubscriptionStatus to an AdditionalInfo. - * - * @param subscriptionStatusList containing details - * @return an AdditionalInfo - */ - @Named("mapListOfSubscriptionStatusToAdditionalInfo") - default AdditionalInfo mapListOfSubscriptionStatusToAdditionalInfo( - final List subscriptionStatusList) { - if (subscriptionStatusList == null || subscriptionStatusList.isEmpty()) { - throw new DataValidationException("Invalid subscriptionStatusList", - "SubscriptionStatus list cannot be null or empty"); - } - - final Map> rejectedSubscriptionsPerDetails = getSubscriptionsPerDetails( - subscriptionStatusList, SubscriptionStatus.Status.REJECTED); - final Map> rejectedCmHandlesPerDetails = - getCmHandlesPerDetails(rejectedSubscriptionsPerDetails); - final List rejectedCmHandles = getAdditionalInfoDetailList(rejectedCmHandlesPerDetails); - - - final Map> pendingSubscriptionsPerDetails = getSubscriptionsPerDetails( - subscriptionStatusList, SubscriptionStatus.Status.PENDING); - final Map> pendingCmHandlesPerDetails = - getCmHandlesPerDetails(pendingSubscriptionsPerDetails); - final List pendingCmHandles = getAdditionalInfoDetailList(pendingCmHandlesPerDetails); - - final AdditionalInfo additionalInfo = new AdditionalInfo(); - additionalInfo.setRejected(rejectedCmHandles); - additionalInfo.setPending(pendingCmHandles); - - return additionalInfo; - } - - private static Map> getSubscriptionsPerDetails( - final List subscriptionStatusList, final SubscriptionStatus.Status status) { - return subscriptionStatusList.stream() - .filter(subscriptionStatus -> subscriptionStatus.getStatus() == status) - .collect(Collectors.groupingBy(SubscriptionStatus::getDetails)); - } - - private static Map> getCmHandlesPerDetails( - final Map> subscriptionsPerDetails) { - return subscriptionsPerDetails.entrySet().stream() - .collect(Collectors.toMap( - Map.Entry::getKey, - entry -> entry.getValue().stream() - .map(SubscriptionStatus::getId) - .collect(Collectors.toList()) - )); - } - - private static List getAdditionalInfoDetailList( - final Map> cmHandlesPerDetails) { - return cmHandlesPerDetails.entrySet().stream() - .map(entry -> { - final AdditionalInfoDetail detail = new AdditionalInfoDetail(); - detail.setDetails(entry.getKey()); - detail.setTargets(entry.getValue()); - return detail; - }).collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java new file mode 100644 index 000000000..3a7e0c6cf --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java @@ -0,0 +1,118 @@ +/* + * ============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.events.cmsubscription; + +import com.hazelcast.map.IMap; +import io.cloudevents.CloudEvent; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; +import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventResponseCloudMapper; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; +import org.onap.cps.spi.model.DataNode; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionDmiOutEventConsumer { + + private final IMap> forwardedSubscriptionEventCache; + private final SubscriptionPersistence subscriptionPersistence; + private final CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper + cmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper; + private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; + private final SubscriptionEventResponseCloudMapper subscriptionEventResponseCloudMapper; + + @Value("${notification.enabled:true}") + private boolean notificationFeatureEnabled; + + @Value("${ncmp.model-loader.subscription:false}") + private boolean subscriptionModelLoaderEnabled; + + /** + * Consume subscription response event. + * + * @param cmSubscriptionDmiOutConsumerRecord the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", + containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") + public void consumeSubscriptionEventResponse( + final ConsumerRecord cmSubscriptionDmiOutConsumerRecord) { + final CloudEvent cloudEvent = cmSubscriptionDmiOutConsumerRecord.value(); + final String eventType = cmSubscriptionDmiOutConsumerRecord.value().getType(); + final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent = + subscriptionEventResponseCloudMapper.toCmSubscriptionDmiOutEvent(cloudEvent); + final String clientId = cmSubscriptionDmiOutEvent.getData().getClientId(); + log.info("subscription event response of clientId: {} is received.", clientId); + final String subscriptionName = cmSubscriptionDmiOutEvent.getData().getSubscriptionName(); + final String subscriptionEventId = clientId + subscriptionName; + boolean createOutcomeResponse = false; + if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { + final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); + dmiNames.remove(cmSubscriptionDmiOutEvent.getData().getDmiName()); + forwardedSubscriptionEventCache.put(subscriptionEventId, dmiNames, + ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); + createOutcomeResponse = forwardedSubscriptionEventCache.get(subscriptionEventId).isEmpty(); + } + if (subscriptionModelLoaderEnabled) { + updateSubscriptionEvent(cmSubscriptionDmiOutEvent); + } + if (createOutcomeResponse + && notificationFeatureEnabled + && hasNoPendingCmHandles(clientId, subscriptionName)) { + cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionDmiOutEvent, eventType); + forwardedSubscriptionEventCache.remove(subscriptionEventId); + } + } + + private boolean hasNoPendingCmHandles(final String clientId, final String subscriptionName) { + final Collection dataNodeSubscription = subscriptionPersistence.getCmHandlesForSubscriptionEvent( + clientId, subscriptionName); + final Map> cmHandleIdToStatusAndDetailsAsMapOriginal = + DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode(dataNodeSubscription); + for (final Map statusAndDetailsMap : cmHandleIdToStatusAndDetailsAsMapOriginal.values()) { + final String status = statusAndDetailsMap.get("status"); + if (SubscriptionStatus.PENDING.toString().equals(status)) { + return false; + } + } + return true; + } + + private void updateSubscriptionEvent(final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent) { + final YangModelSubscriptionEvent yangModelSubscriptionEvent = + cmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper + .toYangModelSubscriptionEvent(cmSubscriptionDmiOutEvent); + subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.java new file mode 100644 index 000000000..99452c6c2 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.java @@ -0,0 +1,105 @@ +/* + * ============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.events.cmsubscription; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfo; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfoDetail; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent; +import org.onap.cps.spi.exceptions.DataValidationException; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper { + + @Mapping(source = "data.subscriptionStatus", target = "data.additionalInfo", + qualifiedByName = "mapListOfSubscriptionStatusToAdditionalInfo") + CmSubscriptionNcmpOutEvent toCmSubscriptionNcmpOutEvent(CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent); + + /** + * Maps list of SubscriptionStatus to an AdditionalInfo. + * + * @param subscriptionStatusList containing details + * @return an AdditionalInfo + */ + @Named("mapListOfSubscriptionStatusToAdditionalInfo") + default AdditionalInfo mapListOfSubscriptionStatusToAdditionalInfo( + final List subscriptionStatusList) { + if (subscriptionStatusList == null || subscriptionStatusList.isEmpty()) { + throw new DataValidationException("Invalid subscriptionStatusList", + "SubscriptionStatus list cannot be null or empty"); + } + + final Map> rejectedSubscriptionsPerDetails = getSubscriptionsPerDetails( + subscriptionStatusList, SubscriptionStatus.Status.REJECTED); + final Map> rejectedCmHandlesPerDetails = + getCmHandlesPerDetails(rejectedSubscriptionsPerDetails); + final List rejectedCmHandles = getAdditionalInfoDetailList(rejectedCmHandlesPerDetails); + + + final Map> pendingSubscriptionsPerDetails = getSubscriptionsPerDetails( + subscriptionStatusList, SubscriptionStatus.Status.PENDING); + final Map> pendingCmHandlesPerDetails = + getCmHandlesPerDetails(pendingSubscriptionsPerDetails); + final List pendingCmHandles = getAdditionalInfoDetailList(pendingCmHandlesPerDetails); + + final AdditionalInfo additionalInfo = new AdditionalInfo(); + additionalInfo.setRejected(rejectedCmHandles); + additionalInfo.setPending(pendingCmHandles); + + return additionalInfo; + } + + private static Map> getSubscriptionsPerDetails( + final List subscriptionStatusList, final SubscriptionStatus.Status status) { + return subscriptionStatusList.stream() + .filter(subscriptionStatus -> subscriptionStatus.getStatus() == status) + .collect(Collectors.groupingBy(SubscriptionStatus::getDetails)); + } + + private static Map> getCmHandlesPerDetails( + final Map> subscriptionsPerDetails) { + return subscriptionsPerDetails.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> entry.getValue().stream() + .map(SubscriptionStatus::getId) + .collect(Collectors.toList()) + )); + } + + private static List getAdditionalInfoDetailList( + final Map> cmHandlesPerDetails) { + return cmHandlesPerDetails.entrySet().stream() + .map(entry -> { + final AdditionalInfoDetail detail = new AdditionalInfoDetail(); + detail.setDetails(entry.getKey()); + detail.setTargets(entry.getValue()); + return detail; + }).collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java new file mode 100644 index 000000000..77eebe36f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java @@ -0,0 +1,55 @@ +/* + * ============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.events.cmsubscription; + +import java.util.List; +import java.util.stream.Collectors; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper { + + @Mapping(source = "data.clientId", target = "clientId") + @Mapping(source = "data.subscriptionName", target = "subscriptionName") + @Mapping(source = "data.subscriptionStatus", target = "predicates.targetCmHandles", + qualifiedByName = "mapSubscriptionStatusToCmHandleTargets") + YangModelSubscriptionEvent toYangModelSubscriptionEvent( + CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent); + + /** + * Maps SubscriptionStatus to list of TargetCmHandle. + * + * @param subscriptionStatus as a list + * @return TargetCmHandle list + */ + @Named("mapSubscriptionStatusToCmHandleTargets") + default List mapSubscriptionStatusToCmHandleTargets( + List subscriptionStatus) { + return subscriptionStatus.stream().map(status -> new YangModelSubscriptionEvent.TargetCmHandle(status.getId(), + org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.fromString(status.getStatus().value()), + status.getDetails())).collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java new file mode 100644 index 000000000..c64ebacb0 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java @@ -0,0 +1,97 @@ +/* + * ============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.events.cmsubscription; + +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 io.cloudevents.CloudEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionNcmpInEventConsumer { + + private final CmSubscriptionNcmpInEventForwarder cmSubscriptionNcmpInEventForwarder; + private final CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper; + private final SubscriptionPersistence subscriptionPersistence; + private final CmSubscriptionEventCloudMapper cmSubscriptionEventCloudMapper; + + @Value("${notification.enabled:true}") + private boolean notificationFeatureEnabled; + + @Value("${ncmp.model-loader.subscription:false}") + private boolean subscriptionModelLoaderEnabled; + + /** + * Consume the specified event. + * + * @param subscriptionEventConsumerRecord the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.subscription-topic}", + containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") + public void consumeSubscriptionEvent(final ConsumerRecord subscriptionEventConsumerRecord) { + final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value(); + final String eventType = subscriptionEventConsumerRecord.value().getType(); + final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent = + cmSubscriptionEventCloudMapper.toCmSubscriptionNcmpInEvent(cloudEvent); + final String eventDatastore = cmSubscriptionNcmpInEvent.getData().getPredicates().getDatastore(); + if (!eventDatastore.equals(PASSTHROUGH_RUNNING.getDatastoreName()) || eventDatastore.equals( + PASSTHROUGH_OPERATIONAL.getDatastoreName())) { + throw new UnsupportedOperationException( + "passthrough datastores are currently only supported for event subscriptions"); + } + if ("CM".equals(cmSubscriptionNcmpInEvent.getData().getDataType().getDataCategory())) { + if (subscriptionModelLoaderEnabled) { + persistSubscriptionEvent(cmSubscriptionNcmpInEvent); + } + if ("subscriptionCreated".equals(cloudEvent.getType())) { + log.info("Subscription for ClientID {} with name {} ...", + cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID(), + cmSubscriptionNcmpInEvent.getData().getSubscription().getName()); + if (notificationFeatureEnabled) { + cmSubscriptionNcmpInEventForwarder.forwardCreateSubscriptionEvent(cmSubscriptionNcmpInEvent, + eventType); + } + } + } else { + log.trace("Non-CM subscription event ignored"); + } + } + + private void persistSubscriptionEvent(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent) { + final YangModelSubscriptionEvent yangModelSubscriptionEvent = + cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(cmSubscriptionNcmpInEvent); + subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java new file mode 100644 index 000000000..4a174954e --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java @@ -0,0 +1,191 @@ +/* + * ============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.events.cmsubscription; + +import com.hazelcast.map.IMap; +import io.cloudevents.CloudEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; +import org.onap.cps.ncmp.api.impl.events.EventsPublisher; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper; +import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.api.inventory.InventoryPersistence; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.Data; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionNcmpInEventForwarder { + + private final InventoryPersistence inventoryPersistence; + private final EventsPublisher eventsPublisher; + private final IMap> forwardedSubscriptionEventCache; + private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; + private final CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper; + private final CmSubscriptionEventCloudMapper cmSubscriptionEventCloudMapper; + private final CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper + cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper; + private final SubscriptionPersistence subscriptionPersistence; + private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + @Value("${app.ncmp.avc.subscription-forward-topic-prefix}") + private String dmiAvcSubscriptionTopicPrefix; + + @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms:30000}") + private int dmiResponseTimeoutInMs; + + /** + * Forward subscription event. + * + * @param cmSubscriptionNcmpInEvent the event to be forwarded + */ + public void forwardCreateSubscriptionEvent(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, + final String eventType) { + final List cmHandleTargets = cmSubscriptionNcmpInEvent.getData().getPredicates().getTargets(); + if (cmHandleTargets == null || cmHandleTargets.isEmpty() || cmHandleTargets.stream() + .anyMatch(id -> (id).contains("*"))) { + throw new UnsupportedOperationException( + "CMHandle targets are required. \"Wildcard\" operations are not yet supported"); + } + final Collection yangModelCmHandles = + inventoryPersistence.getYangModelCmHandles(cmHandleTargets); + final Map>> dmiPropertiesPerCmHandleIdPerServiceName = + DmiServiceNameOrganizer.getDmiPropertiesPerCmHandleIdPerServiceName(yangModelCmHandles); + findDmisAndRespond(cmSubscriptionNcmpInEvent, eventType, cmHandleTargets, + dmiPropertiesPerCmHandleIdPerServiceName); + } + + private void findDmisAndRespond(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, final String eventType, + final List cmHandleTargetsAsStrings, + final Map>> dmiPropertiesPerCmHandleIdPerServiceName) { + final CmSubscriptionDmiOutEvent emptyCmSubscriptionDmiOutEvent = + new CmSubscriptionDmiOutEvent().withData(new Data()); + emptyCmSubscriptionDmiOutEvent.getData() + .setSubscriptionName(cmSubscriptionNcmpInEvent.getData().getSubscription().getName()); + emptyCmSubscriptionDmiOutEvent.getData() + .setClientId(cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID()); + final List cmHandlesThatExistsInDb = + dmiPropertiesPerCmHandleIdPerServiceName.entrySet().stream().map(Map.Entry::getValue).map(Map::keySet) + .flatMap(Set::stream).collect(Collectors.toList()); + + final List targetCmHandlesDoesNotExistInDb = new ArrayList<>(cmHandleTargetsAsStrings); + targetCmHandlesDoesNotExistInDb.removeAll(cmHandlesThatExistsInDb); + + final Set dmisToRespond = new HashSet<>(dmiPropertiesPerCmHandleIdPerServiceName.keySet()); + + if (dmisToRespond.isEmpty() || !targetCmHandlesDoesNotExistInDb.isEmpty()) { + updatesCmHandlesToRejectedAndPersistSubscriptionEvent(cmSubscriptionNcmpInEvent, + targetCmHandlesDoesNotExistInDb); + } + if (dmisToRespond.isEmpty()) { + cmSubscriptionNcmpOutEventPublisher.sendResponse(emptyCmSubscriptionDmiOutEvent, + "subscriptionCreatedStatus"); + } else { + startResponseTimeout(emptyCmSubscriptionDmiOutEvent, dmisToRespond); + final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent = + cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.toCmSubscriptionDmiInEvent( + cmSubscriptionNcmpInEvent); + forwardEventToDmis(dmiPropertiesPerCmHandleIdPerServiceName, cmSubscriptionDmiInEvent, eventType); + } + } + + private void startResponseTimeout(final CmSubscriptionDmiOutEvent emptyCmSubscriptionDmiOutEvent, + final Set dmisToRespond) { + final String subscriptionClientId = emptyCmSubscriptionDmiOutEvent.getData().getClientId(); + final String subscriptionName = emptyCmSubscriptionDmiOutEvent.getData().getSubscriptionName(); + final String subscriptionEventId = subscriptionClientId + subscriptionName; + + forwardedSubscriptionEventCache.put(subscriptionEventId, dmisToRespond, + ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); + final ResponseTimeoutTask responseTimeoutTask = + new ResponseTimeoutTask(forwardedSubscriptionEventCache, cmSubscriptionNcmpOutEventPublisher, + emptyCmSubscriptionDmiOutEvent); + + executorService.schedule(responseTimeoutTask, dmiResponseTimeoutInMs, TimeUnit.MILLISECONDS); + } + + private void forwardEventToDmis(final Map>> dmiNameCmHandleMap, + final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent, final String eventType) { + dmiNameCmHandleMap.forEach((dmiName, cmHandlePropertiesMap) -> { + final List cmHandleTargets = cmHandlePropertiesMap.entrySet().stream().map( + cmHandleAndProperties -> { + final CmHandle cmHandle = new CmHandle(); + cmHandle.setId(cmHandleAndProperties.getKey()); + cmHandle.setAdditionalProperties(cmHandleAndProperties.getValue()); + return cmHandle; + }).collect(Collectors.toList()); + + cmSubscriptionDmiInEvent.getData().getPredicates().setTargets(cmHandleTargets); + final String eventKey = createEventKey(cmSubscriptionDmiInEvent, dmiName); + final String dmiAvcSubscriptionTopic = dmiAvcSubscriptionTopicPrefix + dmiName; + + final CloudEvent cmSubscriptionDmiInCloudEvent = + cmSubscriptionEventCloudMapper.toCloudEvent(cmSubscriptionDmiInEvent, eventKey, eventType); + eventsPublisher.publishCloudEvent(dmiAvcSubscriptionTopic, eventKey, cmSubscriptionDmiInCloudEvent); + }); + } + + private String createEventKey(final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent, final String dmiName) { + return cmSubscriptionDmiInEvent.getData().getSubscription().getClientID() + "-" + + cmSubscriptionDmiInEvent.getData().getSubscription().getName() + "-" + dmiName; + } + + private void updatesCmHandlesToRejectedAndPersistSubscriptionEvent( + final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, + final List targetCmHandlesDoesNotExistInDb) { + final YangModelSubscriptionEvent yangModelSubscriptionEvent = + cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(cmSubscriptionNcmpInEvent); + yangModelSubscriptionEvent.getPredicates() + .setTargetCmHandles(findRejectedCmHandles(targetCmHandlesDoesNotExistInDb, yangModelSubscriptionEvent)); + subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); + } + + private static List findRejectedCmHandles( + final List targetCmHandlesDoesNotExistInDb, + final YangModelSubscriptionEvent yangModelSubscriptionEvent) { + return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles().stream() + .filter(targetCmHandle -> targetCmHandlesDoesNotExistInDb.contains(targetCmHandle.getCmHandleId())) + .map(target -> new YangModelSubscriptionEvent.TargetCmHandle(target.getCmHandleId(), + SubscriptionStatus.REJECTED, "Targets not found")) + .collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java new file mode 100644 index 000000000..ab93f13a2 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java @@ -0,0 +1,52 @@ +/* + * ============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.events.cmsubscription; + +import java.util.List; +import java.util.stream.Collectors; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionNcmpInEventMapper { + + @Mapping(source = "data.subscription.clientID", target = "clientId") + @Mapping(source = "data.subscription.name", target = "subscriptionName") + @Mapping(source = "data.predicates.targets", target = "predicates.targetCmHandles", + qualifiedByName = "mapTargetsToCmHandleTargets") + @Mapping(source = "data.predicates.datastore", target = "predicates.datastore") + YangModelSubscriptionEvent toYangModelSubscriptionEvent(CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent); + + /** + * Maps list of Targets to list of TargetCmHandle. + * + * @param targets list of objects + * @return TargetCmHandle list + */ + @Named("mapTargetsToCmHandleTargets") + default List mapTargetsToCmHandleTargets(List targets) { + return targets.stream().map(YangModelSubscriptionEvent.TargetCmHandle::new) + .collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java new file mode 100644 index 000000000..f1c166453 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java @@ -0,0 +1,35 @@ +/* + * ============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.events.cmsubscription; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper { + + @Mapping(target = "data.predicates.targets", ignore = true) + CmSubscriptionDmiInEvent toCmSubscriptionDmiInEvent( + CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent); + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java new file mode 100644 index 000000000..38cc724be --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java @@ -0,0 +1,153 @@ +/* + * ============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.events.cmsubscription; + +import io.cloudevents.CloudEvent; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.NcmpEventResponseCode; +import org.onap.cps.ncmp.api.impl.events.EventsPublisher; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; +import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionNcmpOutEventPublisher { + + private final SubscriptionPersistence subscriptionPersistence; + + private final EventsPublisher outcomeEventsPublisher; + + private final CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper + cmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper; + + private final SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper; + + @Value("${app.ncmp.avc.subscription-outcome-topic:subscription-response}") + private String subscriptionOutcomeEventTopic; + + /** + * This is for construction of outcome message to be published for client apps. + * + * @param cmSubscriptionDmiOutEvent event produced by Dmi Plugin + */ + public void sendResponse(final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent, final String eventKey) { + final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent = + formCmSubscriptionNcmpOutEvent(cmSubscriptionDmiOutEvent); + final String subscriptionClientId = cmSubscriptionDmiOutEvent.getData().getClientId(); + final String subscriptionName = cmSubscriptionDmiOutEvent.getData().getSubscriptionName(); + final String subscriptionEventId = subscriptionClientId + subscriptionName; + final CloudEvent subscriptionOutcomeCloudEvent = + subscriptionOutcomeCloudMapper.toCloudEvent(cmSubscriptionNcmpOutEvent, + subscriptionEventId, eventKey); + outcomeEventsPublisher.publishCloudEvent(subscriptionOutcomeEventTopic, + subscriptionEventId, subscriptionOutcomeCloudEvent); + } + + private CmSubscriptionNcmpOutEvent formCmSubscriptionNcmpOutEvent( + final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent) { + final Map> cmHandleIdToStatusAndDetailsAsMap = + DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode( + subscriptionPersistence.getCmHandlesForSubscriptionEvent( + cmSubscriptionDmiOutEvent.getData().getClientId(), + cmSubscriptionDmiOutEvent.getData().getSubscriptionName())); + final List + subscriptionStatusList = + mapCmHandleIdStatusDetailsMapToSubscriptionStatusList(cmHandleIdToStatusAndDetailsAsMap); + cmSubscriptionDmiOutEvent.getData().setSubscriptionStatus(subscriptionStatusList); + return fromDmiOutEvent(cmSubscriptionDmiOutEvent, + decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap)); + } + + private static List + mapCmHandleIdStatusDetailsMapToSubscriptionStatusList( + final Map> cmHandleIdToStatusAndDetailsAsMap) { + return cmHandleIdToStatusAndDetailsAsMap.entrySet() + .stream().map(entryset -> { + final org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus + subscriptionStatus = new org.onap.cps.ncmp.events.cmsubscription1_0_0 + .dmi_to_ncmp.SubscriptionStatus(); + final String cmHandleId = entryset.getKey(); + final Map statusAndDetailsMap = entryset.getValue(); + final String status = statusAndDetailsMap.get("status"); + final String details = statusAndDetailsMap.get("details"); + subscriptionStatus.setId(cmHandleId); + subscriptionStatus.setStatus( + org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp + .SubscriptionStatus.Status.fromValue(status)); + subscriptionStatus.setDetails(details); + return subscriptionStatus; + }).collect(Collectors.toList()); + } + + private NcmpEventResponseCode decideOnNcmpEventResponseCodeForSubscription( + final Map> cmHandleIdToStatusAndDetailsAsMap) { + + final boolean isAllTargetsPending = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap, + SubscriptionStatus.PENDING); + + final boolean isAllTargetsRejected = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap, + SubscriptionStatus.REJECTED); + + final boolean isAllTargetsAccepted = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap, + SubscriptionStatus.ACCEPTED); + + if (isAllTargetsAccepted) { + return NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION; + } else if (isAllTargetsRejected) { + return NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE; + } else if (isAllTargetsPending) { + return NcmpEventResponseCode.SUBSCRIPTION_PENDING; + } else { + return NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION; + } + } + + private boolean isAllTargetCmHandleStatusMatch( + final Map> cmHandleIdToStatusAndDetailsAsMap, + final SubscriptionStatus subscriptionStatus) { + return cmHandleIdToStatusAndDetailsAsMap.values().stream() + .allMatch(entryset -> entryset.containsValue(subscriptionStatus.toString())); + } + + private CmSubscriptionNcmpOutEvent fromDmiOutEvent( + final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent, + final NcmpEventResponseCode ncmpEventResponseCode) { + + final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent = + cmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.toCmSubscriptionNcmpOutEvent( + cmSubscriptionDmiOutEvent); + cmSubscriptionNcmpOutEvent.getData().setStatusCode(Integer.parseInt(ncmpEventResponseCode.getStatusCode())); + cmSubscriptionNcmpOutEvent.getData().setStatusMessage(ncmpEventResponseCode.getStatusMessage()); + + return cmSubscriptionNcmpOutEvent; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java new file mode 100644 index 000000000..7f8cbf676 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java @@ -0,0 +1,52 @@ +/* + * ============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.events.cmsubscription; + +import com.hazelcast.map.IMap; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; + +@Slf4j +@RequiredArgsConstructor +public class ResponseTimeoutTask implements Runnable { + + private final IMap> forwardedSubscriptionEventCache; + private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; + private final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent; + + @Override + public void run() { + generateTimeoutResponse(); + } + + private void generateTimeoutResponse() { + final String subscriptionClientId = cmSubscriptionDmiOutEvent.getData().getClientId(); + final String subscriptionName = cmSubscriptionDmiOutEvent.getData().getSubscriptionName(); + final String subscriptionEventId = subscriptionClientId + subscriptionName; + if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { + cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionDmiOutEvent, + "subscriptionCreatedStatus"); + forwardedSubscriptionEventCache.remove(subscriptionEventId); + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapper.java new file mode 100644 index 000000000..5bc38e1dc --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapper.java @@ -0,0 +1,86 @@ +/* + * ============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.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.cloudevents.CloudEvent; +import io.cloudevents.core.CloudEventUtils; +import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.data.PojoCloudEventData; +import io.cloudevents.jackson.PojoCloudEventDataMapper; +import java.net.URI; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class CmSubscriptionEventCloudMapper { + + private final ObjectMapper objectMapper; + + private static String randomId = UUID.randomUUID().toString(); + + /** + * Maps CloudEvent object to CmSubscriptionNcmpInEvent. + * + * @param cloudEvent object. + * @return CmSubscriptionNcmpInEvent deserialized. + */ + public CmSubscriptionNcmpInEvent toCmSubscriptionNcmpInEvent(final CloudEvent cloudEvent) { + final PojoCloudEventData deserializedCloudEvent = CloudEventUtils + .mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, CmSubscriptionNcmpInEvent.class)); + if (deserializedCloudEvent == null) { + log.debug("No data found in the consumed event"); + return null; + } else { + final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent = deserializedCloudEvent.getValue(); + log.debug("Consuming event {}", cmSubscriptionNcmpInEvent); + return cmSubscriptionNcmpInEvent; + } + } + + /** + * Maps CmSubscriptionDmiInEvent to a CloudEvent. + * + * @param cmSubscriptionDmiInEvent object. + * @param eventKey as String. + * @return CloudEvent built. + */ + public CloudEvent toCloudEvent(final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent, final String eventKey, + final String eventType) { + try { + return CloudEventBuilder.v1().withId(randomId) + .withSource(URI.create(cmSubscriptionDmiInEvent.getData().getSubscription().getClientID())) + .withType(eventType).withExtension("correlationid", eventKey) + .withDataSchema(URI.create("urn:cps:" + CmSubscriptionDmiInEvent.class.getName() + ":1.0.0")) + .withData(objectMapper.writeValueAsBytes(cmSubscriptionDmiInEvent)).build(); + } catch (final JsonProcessingException jsonProcessingException) { + log.error("The Cloud Event could not be constructed", jsonProcessingException); + } + return null; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapper.java deleted file mode 100644 index 1561edc44..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapper.java +++ /dev/null @@ -1,90 +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.utils; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.cloudevents.CloudEvent; -import io.cloudevents.core.CloudEventUtils; -import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.core.data.PojoCloudEventData; -import io.cloudevents.jackson.PojoCloudEventDataMapper; -import java.net.URI; -import java.util.UUID; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -@RequiredArgsConstructor -public class SubscriptionEventCloudMapper { - - private final ObjectMapper objectMapper; - - private static String randomId = UUID.randomUUID().toString(); - - /** - * Maps CloudEvent object to SubscriptionEvent. - * - * @param cloudEvent object. - * @return SubscriptionEvent deserialized. - */ - public SubscriptionEvent toSubscriptionEvent(final CloudEvent cloudEvent) { - final PojoCloudEventData deserializedCloudEvent = CloudEventUtils - .mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, SubscriptionEvent.class)); - if (deserializedCloudEvent == null) { - log.debug("No data found in the consumed event"); - return null; - } else { - final SubscriptionEvent subscriptionEvent = deserializedCloudEvent.getValue(); - log.debug("Consuming event {}", subscriptionEvent); - return subscriptionEvent; - } - } - - /** - * Maps SubscriptionEvent to a CloudEvent. - * - * @param ncmpSubscriptionEvent object. - * @param eventKey as String. - * @return CloudEvent built. - */ - public CloudEvent toCloudEvent( - final org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent ncmpSubscriptionEvent, - final String eventKey, final String eventType) { - try { - return CloudEventBuilder.v1() - .withId(randomId) - .withSource(URI.create(ncmpSubscriptionEvent.getData().getSubscription().getClientID())) - .withType(eventType) - .withExtension("correlationid", eventKey) - .withDataSchema(URI.create("urn:cps:" - + org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi - .SubscriptionEvent.class.getName() + ":1.0.0")) - .withData(objectMapper.writeValueAsBytes(ncmpSubscriptionEvent)).build(); - } catch (final JsonProcessingException jsonProcessingException) { - log.error("The Cloud Event could not be constructed", jsonProcessingException); - } - return null; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapper.java index e00bb16b9..0721d1d56 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapper.java @@ -27,7 +27,7 @@ import io.cloudevents.core.data.PojoCloudEventData; import io.cloudevents.jackson.PojoCloudEventDataMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; import org.springframework.stereotype.Component; @Slf4j @@ -38,21 +38,21 @@ public class SubscriptionEventResponseCloudMapper { private final ObjectMapper objectMapper; /** - * Maps CloudEvent object to SubscriptionEventResponse. + * Maps CloudEvent object to CmSubscriptionDmiOutEvent. * * @param cloudEvent object - * @return SubscriptionEventResponse deserialized + * @return CmSubscriptionDmiOutEvent deserialized */ - public SubscriptionEventResponse toSubscriptionEventResponse(final CloudEvent cloudEvent) { - final PojoCloudEventData deserializedCloudEvent = CloudEventUtils - .mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, SubscriptionEventResponse.class)); + public CmSubscriptionDmiOutEvent toCmSubscriptionDmiOutEvent(final CloudEvent cloudEvent) { + final PojoCloudEventData deserializedCloudEvent = CloudEventUtils + .mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, CmSubscriptionDmiOutEvent.class)); if (deserializedCloudEvent == null) { log.debug("No data found in the consumed subscription response event"); return null; } else { - final SubscriptionEventResponse subscriptionEventResponse = deserializedCloudEvent.getValue(); - log.debug("Consuming subscription response event {}", subscriptionEventResponse); - return subscriptionEventResponse; + final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent = deserializedCloudEvent.getValue(); + log.debug("Consuming subscription response event {}", cmSubscriptionDmiOutEvent); + return cmSubscriptionDmiOutEvent; } } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapper.java index 9ea448706..af629a6bd 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapper.java @@ -28,7 +28,7 @@ import java.net.URI; import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.SubscriptionEventOutcome; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent; import org.springframework.stereotype.Component; @Slf4j @@ -41,12 +41,12 @@ public class SubscriptionOutcomeCloudMapper { private static String randomId = UUID.randomUUID().toString(); /** - * Maps SubscriptionEventOutcome to a CloudEvent. + * Maps CmSubscriptionNcmpOutEvent to a CloudEvent. * - * @param subscriptionEventOutcome object + * @param cmSubscriptionNcmpOutEvent object * @return CloudEvent */ - public CloudEvent toCloudEvent(final SubscriptionEventOutcome subscriptionEventOutcome, + public CloudEvent toCloudEvent(final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent, final String eventKey, final String eventType) { try { return CloudEventBuilder.v1() @@ -54,8 +54,8 @@ public class SubscriptionOutcomeCloudMapper { .withSource(URI.create("NCMP")) .withType(eventType) .withExtension("correlationid", eventKey) - .withDataSchema(URI.create("urn:cps:" + SubscriptionEventOutcome.class.getName() + ":1.0.0")) - .withData(objectMapper.writeValueAsBytes(subscriptionEventOutcome)).build(); + .withDataSchema(URI.create("urn:cps:" + CmSubscriptionNcmpOutEvent.class.getName() + ":1.0.0")) + .withData(objectMapper.writeValueAsBytes(cmSubscriptionNcmpOutEvent)).build(); } catch (final JsonProcessingException jsonProcessingException) { log.error("The Cloud Event could not be constructed", jsonProcessingException); } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapperSpec.groovy deleted file mode 100644 index b3d81e33c..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/ClientSubscriptionEventMapperSpec.groovy +++ /dev/null @@ -1,60 +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.events.avcsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent; -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class ClientSubscriptionEventMapperSpec extends Specification { - - ClientSubscriptionEventMapper objectUnderTest = Mappers.getMapper(ClientSubscriptionEventMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map clients subscription event to ncmps subscription event'() { - given: 'a Subscription Event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - when: 'the client event is mapped to a ncmp subscription event' - def result = objectUnderTest.toNcmpSubscriptionEvent(testEventToMap) - then: 'the resulting ncmp subscription event contains the correct clientId' - assert result.getData().getSubscription().getClientID() == "SCO-9989752" - and: 'subscription name' - assert result.getData().getSubscription().getName() == "cm-subscription-001" - and: 'is tagged value is false' - assert result.getData().getSubscription().getIsTagged() == false - and: 'data category is CM' - assert result.getData().getDataType().getDataCategory() == 'CM' - and: 'predicate targets is null' - assert result.getData().getPredicates().getTargets() == [] - and: 'datastore is passthrough-running' - assert result.getData().getPredicates().getDatastore() == 'ncmp-datastore:passthrough-running' - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumerSpec.groovy deleted file mode 100644 index 430d12207..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumerSpec.groovy +++ /dev/null @@ -1,108 +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.events.avcsubscription - -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.subscriptions.SubscriptionPersistence -import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventCloudMapper -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent; -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class SubscriptionEventConsumerSpec extends MessagingBaseSpec { - - def mockSubscriptionEventForwarder = Mock(SubscriptionEventForwarder) - def mockSubscriptionEventMapper = Mock(SubscriptionEventMapper) - def mockSubscriptionPersistence = Mock(SubscriptionPersistence) - def subscriptionEventCloudMapper = new SubscriptionEventCloudMapper(new ObjectMapper()) - def objectUnderTest = new SubscriptionEventConsumer(mockSubscriptionEventForwarder, mockSubscriptionEventMapper, mockSubscriptionPersistence, subscriptionEventCloudMapper) - - def yangModelSubscriptionEvent = new YangModelSubscriptionEvent() - - @Autowired - JsonObjectMapper jsonObjectMapper - - @Autowired - ObjectMapper objectMapper - - - def 'Consume, persist and forward valid CM create message'() { - given: 'an event with data category CM' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - testEventSent.getData().getDataType().setDataCategory(dataCategory) - def testCloudEventSent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(testEventSent)) - .withId('subscriptionCreated') - .withType(dataType) - .withSource(URI.create('some-resource')) - .withExtension('correlationid', 'test-cmhandle1').build() - def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) - and: 'notifications are enabled' - objectUnderTest.notificationFeatureEnabled = isNotificationEnabled - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = isModelLoaderEnabled - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(consumerRecord) - then: 'the event is mapped to a yangModelSubscription' - numberOfTimesToPersist * mockSubscriptionEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent - and: 'the event is persisted' - numberOfTimesToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) - and: 'the event is forwarded' - numberOfTimesToForward * mockSubscriptionEventForwarder.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreated') - where: 'given values are used' - scenario | dataCategory | dataType | isNotificationEnabled | isModelLoaderEnabled || numberOfTimesToForward || numberOfTimesToPersist - 'Both model loader and notification are enabled' | 'CM' | 'subscriptionCreated' | true | true || 1 || 1 - 'Both model loader and notification are disabled' | 'CM' | 'subscriptionCreated' | false | false || 0 || 0 - 'Model loader enabled and notification disabled' | 'CM' | 'subscriptionCreated' | false | true || 0 || 1 - 'Model loader disabled and notification enabled' | 'CM' | 'subscriptionCreated' | true | false || 1 || 0 - 'Flags are enabled but data category is FM' | 'FM' | 'subscriptionCreated' | true | true || 0 || 0 - 'Flags are enabled but data type is UPDATE' | 'CM' | 'subscriptionUpdated' | true | true || 0 || 1 - } - - def 'Consume event with wrong datastore causes an exception'() { - given: 'an event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - and: 'datastore is set to a passthrough-running datastore' - testEventSent.getData().getPredicates().setDatastore('operational') - def testCloudEventSent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(testEventSent)) - .withId('some-event-id') - .withType('some-event-type') - .withSource(URI.create('some-resource')) - .withExtension('correlationid', 'test-cmhandle1').build() - def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(consumerRecord) - then: 'an operation not supported exception is thrown' - thrown(UnsupportedOperationException) - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy deleted file mode 100644 index dd93bf6f0..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy +++ /dev/null @@ -1,203 +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.events.avcsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import com.hazelcast.map.IMap -import io.cloudevents.CloudEvent -import io.cloudevents.core.CloudEventUtils -import io.cloudevents.core.data.PojoCloudEventData -import io.cloudevents.jackson.PojoCloudEventDataMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus -import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventCloudMapper -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent.TargetCmHandle -import org.onap.cps.ncmp.api.inventory.InventoryPersistence -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.Data -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.CmHandle; -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.spockframework.spring.SpringBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.util.concurrent.BlockingVariable -import java.util.concurrent.TimeUnit - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, SubscriptionEventForwarder]) -class SubscriptionEventForwarderSpec extends MessagingBaseSpec { - - @Autowired - SubscriptionEventForwarder objectUnderTest - - @SpringBean - InventoryPersistence mockInventoryPersistence = Mock(InventoryPersistence) - @SpringBean - EventsPublisher mockSubscriptionEventPublisher = Mock(EventsPublisher) - @SpringBean - IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) - @SpringBean - SubscriptionEventCloudMapper subscriptionEventCloudMapper = new SubscriptionEventCloudMapper(new ObjectMapper()) - @SpringBean - SubscriptionEventResponseOutcome mockSubscriptionEventResponseOutcome = Mock(SubscriptionEventResponseOutcome) - @SpringBean - SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) - @SpringBean - SubscriptionEventMapper subscriptionEventMapper = Mappers.getMapper(SubscriptionEventMapper) - @SpringBean - ClientSubscriptionEventMapper clientSubscriptionEventMapper = Mappers.getMapper(ClientSubscriptionEventMapper) - @Autowired - JsonObjectMapper jsonObjectMapper - @Autowired - ObjectMapper objectMapper - - def 'Forward valid CM create subscription and simulate timeout'() { - given: 'an event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - and: 'the InventoryPersistence returns private properties for the supplied CM Handles' - 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [ - createYangModelCmHandleWithDmiProperty(1, 1,"shape","circle"), - createYangModelCmHandleWithDmiProperty(2, 1,"shape","square") - ] - and: 'the thread creation delay is reduced to 2 seconds for testing' - objectUnderTest.dmiResponseTimeoutInMs = 2000 - and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' - def block = new BlockingVariable(5) - when: 'the valid event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreated') - then: 'An asynchronous call is made to the blocking variable' - block.get() - then: 'the event is added to the forwarded subscription event cache' - 1 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1"] as Set, 600, TimeUnit.SECONDS) - and: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' - 1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", - cloudEvent -> { - def targets = toSubscriptionEvent(cloudEvent).getData().getPredicates().getTargets() - def cmHandle2 = createCmHandle('CMHandle2', ['shape':'square'] as Map) - def cmHandle1 = createCmHandle('CMHandle1', ['shape':'circle'] as Map) - targets == [cmHandle2, cmHandle1] - } - ) - and: 'a separate thread has been created where the map is polled' - 1 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true - 1 * mockSubscriptionEventResponseOutcome.sendResponse(*_) - and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' - 1 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)} - } - - def 'Forward CM create subscription where target CM Handles are #scenario'() { - given: 'an event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - and: 'the target CMHandles are set to #scenario' - testEventSent.getData().getPredicates().setTargets(invalidTargets) - when: 'the event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'some-event-type') - then: 'an operation not supported exception is thrown' - thrown(UnsupportedOperationException) - where: - scenario | invalidTargets - 'null' | null - 'empty' | [] - 'wildcard' | ['CMHandle*'] - } - - def 'Forward valid CM create subscription where targets are not associated to any existing CMHandles'() { - given: 'an event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - and: 'a subscription event response' - def emptySubscriptionEventResponse = new SubscriptionEventResponse().withData(new Data()); - emptySubscriptionEventResponse.getData().setSubscriptionName('cm-subscription-001'); - emptySubscriptionEventResponse.getData().setClientId('SCO-9989752'); - and: 'the cm handles will be rejected' - def rejectedCmHandles = [new TargetCmHandle('CMHandle1', SubscriptionStatus.REJECTED, 'Cm handle does not exist'), - new TargetCmHandle('CMHandle2',SubscriptionStatus.REJECTED, 'Cm handle does not exist'), - new TargetCmHandle('CMHandle3',SubscriptionStatus.REJECTED, 'Cm handle does not exist')] - and: 'a yang model subscription event will be saved into the db with rejected cm handles' - def yangModelSubscriptionEvent = subscriptionEventMapper.toYangModelSubscriptionEvent(testEventSent) - yangModelSubscriptionEvent.getPredicates().setTargetCmHandles(rejectedCmHandles) - and: 'the InventoryPersistence returns no private properties for the supplied CM Handles' - 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [] - and: 'the thread creation delay is reduced to 2 seconds for testing' - objectUnderTest.dmiResponseTimeoutInMs = 2000 - and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' - def block = new BlockingVariable(5) - when: 'the valid event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreatedStatus') - then: 'the event is not added to the forwarded subscription event cache' - 0 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1", "DMIName2"] as Set) - and: 'the event is not being forwarded with the CMHandle private properties and does not provides a valid listenable future' - 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", - cloudEvent -> { - def targets = toSubscriptionEvent(cloudEvent).getData().getPredicates().getTargets() - def cmHandle2 = createCmHandle('CMHandle2', ['shape':'square'] as Map) - def cmHandle1 = createCmHandle('CMHandle1', ['shape':'circle'] as Map) - targets == [cmHandle2, cmHandle1] - } - ) - 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", - cloudEvent -> { - def targets = toSubscriptionEvent(cloudEvent).getData().getPredicates().getTargets() - def cmHandle3 = createCmHandle('CMHandle3', ['shape':'triangle'] as Map) - targets == [cmHandle3] - } - ) - and: 'a separate thread has been created where the map is polled' - 0 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true - 0 * mockForwardedSubscriptionEventCache.get(_) - and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' - 0 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)} - and: 'the persistence service save target cm handles of the yang model subscription event as rejected ' - 1 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) - and: 'subscription outcome has been sent' - 1 * mockSubscriptionEventResponseOutcome.sendResponse(emptySubscriptionEventResponse, 'subscriptionCreatedStatus') - } - - static def createYangModelCmHandleWithDmiProperty(id, dmiId,propertyName, propertyValue) { - return new YangModelCmHandle(id:"CMHandle" + id, dmiDataServiceName: "DMIName" + dmiId, dmiProperties: [new YangModelCmHandle.Property(propertyName,propertyValue)]) - } - - static def createCmHandle(id, additionalProperties) { - def cmHandle = new CmHandle(); - cmHandle.setId(id) - cmHandle.setAdditionalProperties(additionalProperties) - return cmHandle - } - - def toSubscriptionEvent(cloudEvent) { - final PojoCloudEventData deserializedCloudEvent = CloudEventUtils - .mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, - org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent.class)); - if (deserializedCloudEvent == null) { - return null; - } else { - return deserializedCloudEvent.getValue(); - } - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapperSpec.groovy deleted file mode 100644 index a2a80e854..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapperSpec.groovy +++ /dev/null @@ -1,79 +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.events.avcsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.events.avcsubscription.SubscriptionEventMapper -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class SubscriptionEventMapperSpec extends Specification { - - SubscriptionEventMapper objectUnderTest = Mappers.getMapper(SubscriptionEventMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map subscription event to yang model subscription event where #scenario'() { - given: 'a Subscription Event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - when: 'the event is mapped to a yang model subscription' - def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) - then: 'the resulting yang model subscription event contains the correct clientId' - assert result.clientId == "SCO-9989752" - and: 'subscription name' - assert result.subscriptionName == "cm-subscription-001" - and: 'is tagged value is false' - assert !result.isTagged - and: 'predicate targets ' - assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2", "CMHandle3"] - and: 'the status for these targets is set to pending' - assert result.predicates.targetCmHandles.status == [SubscriptionStatus.PENDING, SubscriptionStatus.PENDING, SubscriptionStatus.PENDING] - and: 'the topic is null' - assert result.topic == null - } - - def 'Map empty subscription event to yang model subscription event'() { - given: 'a new Subscription Event with no data' - def testEventToMap = new SubscriptionEvent() - when: 'the event is mapped to a yang model subscription' - def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) - then: 'the resulting yang model subscription event contains null clientId' - assert result.clientId == null - and: 'subscription name is null' - assert result.subscriptionName == null - and: 'is tagged value is false' - assert result.isTagged == false - and: 'predicates is null' - assert result.predicates == null - and: 'the topic is null' - assert result.topic == null - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy deleted file mode 100644 index 3e6d7a82d..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy +++ /dev/null @@ -1,142 +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.events.avcsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import com.hazelcast.map.IMap -import io.cloudevents.CloudEvent -import io.cloudevents.core.builder.CloudEventBuilder -import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistenceImpl -import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventResponseCloudMapper -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.spi.model.DataNodeBuilder -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class SubscriptionEventResponseConsumerSpec extends MessagingBaseSpec { - - @Autowired - JsonObjectMapper jsonObjectMapper - - @Autowired - ObjectMapper objectMapper - - IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) - def mockSubscriptionPersistence = Mock(SubscriptionPersistenceImpl) - def mockSubscriptionEventResponseMapper = Mock(SubscriptionEventResponseMapper) - def mockSubscriptionEventResponseOutcome = Mock(SubscriptionEventResponseOutcome) - def mockSubscriptionEventResponseCloudMapper = new SubscriptionEventResponseCloudMapper(new ObjectMapper()) - - def objectUnderTest = new SubscriptionEventResponseConsumer(mockForwardedSubscriptionEventCache, - mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockSubscriptionEventResponseOutcome, mockSubscriptionEventResponseCloudMapper) - - def 'Consume Subscription Event Response where all DMIs have responded'() { - given: 'a consumer record including cloud event having subscription response' - def consumerRecordWithCloudEventAndSubscriptionResponse = getConsumerRecord() - and: 'a subscription response event' - def subscriptionResponseEvent = getSubscriptionResponseEvent() - and: 'a subscription event response and notifications are enabled' - objectUnderTest.notificationFeatureEnabled = notificationEnabled - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled - and: 'subscription persistence service returns data node includes no pending cm handle' - mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [getDataNode()] - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEventResponse(consumerRecordWithCloudEventAndSubscriptionResponse) - then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' - 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['some-dmi-name'] as Set) - and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> ([] as Set) - and: 'the response event is map to yang model' - numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) - and: 'the response event is persisted into the db' - numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) - and: 'the subscription event is removed from the map' - numberOfTimeToRemove * mockForwardedSubscriptionEventCache.remove('SCO-9989752cm-subscription-001') - and: 'a response outcome has been created' - numberOfTimeToResponse * mockSubscriptionEventResponseOutcome.sendResponse(subscriptionResponseEvent, 'subscriptionCreated') - where: 'the following values are used' - scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist || numberOfTimeToRemove || numberOfTimeToResponse - 'Both model loader and notification are enabled' | true | true || 1 || 1 || 1 - 'Both model loader and notification are disabled' | false | false || 0 || 0 || 0 - 'Model loader enabled and notification disabled' | true | false || 1 || 0 || 0 - 'Model loader disabled and notification enabled' | false | true || 0 || 1 || 1 - } - - def 'Consume Subscription Event Response where another DMI has not yet responded'() { - given: 'a subscription event response and notifications are enabled' - objectUnderTest.notificationFeatureEnabled = notificationEnabled - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEventResponse(getConsumerRecord()) - then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' - 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['responded-dmi', 'non-responded-dmi'] as Set) - and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['non-responded-dmi'] as Set) - and: 'the response event is map to yang model' - numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) - and: 'the response event is persisted into the db' - numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) - and: 'the subscription event is removed from the map' - and: 'the subscription event is not removed from the map' - 0 * mockForwardedSubscriptionEventCache.remove(_) - and: 'a response outcome has not been created' - 0 * mockSubscriptionEventResponseOutcome.sendResponse(*_) - where: 'the following values are used' - scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist - 'Both model loader and notification are enabled' | true | true || 1 - 'Both model loader and notification are disabled' | false | false || 0 - 'Model loader enabled and notification disabled' | true | false || 1 - 'Model loader disabled and notification enabled' | false | true || 0 - } - - def getSubscriptionResponseEvent() { - def subscriptionResponseJsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - return jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, SubscriptionEventResponse.class) - } - - def getCloudEventHavingSubscriptionResponseEvent() { - return CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(getSubscriptionResponseEvent())) - .withId('some-id') - .withType('subscriptionCreated') - .withSource(URI.create('NCMP')).build() - } - - def getConsumerRecord() { - return new ConsumerRecord('topic-name', 0, 0, 'event-key', getCloudEventHavingSubscriptionResponseEvent()) - } - - def getDataNode() { - def leaves = [status:'ACCEPTED', cmHandleId:'cmhandle1'] as Map - return new DataNodeBuilder().withDataspace('NCMP-Admin') - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves(leaves).build() - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapperSpec.groovy deleted file mode 100644 index d07d9bb99..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseMapperSpec.groovy +++ /dev/null @@ -1,60 +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.events.avcsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse; -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class SubscriptionEventResponseMapperSpec extends Specification { - - SubscriptionEventResponseMapper objectUnderTest = Mappers.getMapper(SubscriptionEventResponseMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map subscription response event to yang model subscription event'() { - given: 'a Subscription Response Event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEventResponse.class) - when: 'the event is mapped to a yang model subscription' - def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) - then: 'the resulting yang model subscription event contains the correct clientId' - assert result.clientId == "SCO-9989752" - and: 'subscription name' - assert result.subscriptionName == "cm-subscription-001" - and: 'predicate targets cm handle size as expected' - assert result.predicates.targetCmHandles.size() == 4 - and: 'predicate targets cm handle ids as expected' - assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2", "CMHandle3", "CMHandle4"] - and: 'the status for these targets is set to expected values' - assert result.predicates.targetCmHandles.status == [SubscriptionStatus.REJECTED, SubscriptionStatus.REJECTED, SubscriptionStatus.PENDING, SubscriptionStatus.PENDING] - } - -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy deleted file mode 100644 index a6c8712a3..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy +++ /dev/null @@ -1,124 +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.events.avcsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import io.cloudevents.CloudEvent -import io.cloudevents.core.builder.CloudEventBuilder -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.NcmpEventResponseCode -import org.onap.cps.ncmp.api.impl.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence -import org.onap.cps.ncmp.api.impl.utils.DataNodeBaseSpec -import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.SubscriptionEventOutcome; -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.spockframework.spring.SpringBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, SubscriptionOutcomeMapper, SubscriptionEventResponseOutcome]) -class SubscriptionEventResponseOutcomeSpec extends DataNodeBaseSpec { - - @Autowired - SubscriptionEventResponseOutcome objectUnderTest - - @SpringBean - SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) - @SpringBean - EventsPublisher mockSubscriptionEventOutcomePublisher = Mock(EventsPublisher) - @SpringBean - SubscriptionOutcomeMapper subscriptionOutcomeMapper = Mappers.getMapper(SubscriptionOutcomeMapper) - @SpringBean - SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper = new SubscriptionOutcomeCloudMapper(new ObjectMapper()) - - @Autowired - JsonObjectMapper jsonObjectMapper - - @Autowired - ObjectMapper objectMapper - - def 'Send response to the client apps successfully'() { - given: 'a subscription response event' - def subscriptionResponseJsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, SubscriptionEventResponse.class) - and: 'a subscription outcome event' - def subscriptionOutcomeJsonData = TestUtils.getResourceFileContent('avcSubscriptionOutcomeEvent2.json') - def subscriptionOutcomeEvent = jsonObjectMapper.convertJsonString(subscriptionOutcomeJsonData, SubscriptionEventOutcome.class) - and: 'a random id for the cloud event' - SubscriptionOutcomeCloudMapper.randomId = 'some-id' - and: 'a cloud event containing the outcome event' - def testCloudEventSent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(subscriptionOutcomeEvent)) - .withId('some-id') - .withType('subscriptionCreatedStatus') - .withDataSchema(URI.create('urn:cps:' + 'org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.SubscriptionEventOutcome' + ':1.0.0')) - .withExtension("correlationid", 'SCO-9989752cm-subscription-001') - .withSource(URI.create('NCMP')).build() - and: 'the persistence service return a data node that includes pending cm handles that makes it partial success' - mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [dataNode4] - when: 'the response is being sent' - objectUnderTest.sendResponse(subscriptionResponseEvent, 'subscriptionCreatedStatus') - then: 'the publisher publish the cloud event with itself and expected parameters' - 1 * mockSubscriptionEventOutcomePublisher.publishCloudEvent('subscription-response', 'SCO-9989752cm-subscription-001', testCloudEventSent) - } - - def 'Create subscription outcome message as expected'() { - given: 'a subscription response event' - def subscriptionResponseJsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, SubscriptionEventResponse.class) - and: 'a subscription outcome event' - def subscriptionOutcomeJsonData = TestUtils.getResourceFileContent('avcSubscriptionOutcomeEvent.json') - def subscriptionOutcomeEvent = jsonObjectMapper.convertJsonString(subscriptionOutcomeJsonData, SubscriptionEventOutcome.class) - and: 'a status code and status message a per #scenarios' - subscriptionOutcomeEvent.getData().setStatusCode(statusCode) - subscriptionOutcomeEvent.getData().setStatusMessage(statusMessage) - when: 'a subscription event outcome message is being formed' - def result = objectUnderTest.fromSubscriptionEventResponse(subscriptionResponseEvent, ncmpEventResponseCode) - then: 'the result will be equal to event outcome' - result == subscriptionOutcomeEvent - where: 'the following values are used' - scenario | ncmpEventResponseCode || statusMessage || statusCode - 'is full outcome' | NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION || 'successfully applied subscription' || 1 - 'is partial outcome' | NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION || 'partially applied subscription' || 104 - } - - def 'Check cm handle id to status map to see if it is a full outcome response'() { - when: 'is full outcome response evaluated' - def response = objectUnderTest.decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap) - then: 'the result will be as expected' - response == expectedOutcomeResponseDecision - where: 'the following values are used' - scenario | cmHandleIdToStatusAndDetailsAsMap || expectedOutcomeResponseDecision - 'The map contains PENDING status' | [CMHandle1: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_PENDING - 'The map contains ACCEPTED status' | [CMHandle1: [details:'',status:'ACCEPTED'] as Map] as Map || NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION - 'The map contains REJECTED status' | [CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE - 'The map contains PENDING and PENDING statuses' | [CMHandle1: [details:'Some details',status:'PENDING'] as Map, CMHandle2: [details:'Some details',status:'PENDING'] as Map as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_PENDING - 'The map contains ACCEPTED and ACCEPTED statuses' | [CMHandle1: [details:'',status:'ACCEPTED'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map || NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION - 'The map contains REJECTED and REJECTED statuses' | [CMHandle1: [details:'Reject details',status:'REJECTED'] as Map, CMHandle2: [details:'Reject details',status:'REJECTED'] as Map as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE - 'The map contains PENDING and ACCEPTED statuses' | [CMHandle1: [details:'Some details',status:'PENDING'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION - 'The map contains REJECTED and ACCEPTED statuses' | [CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION - 'The map contains PENDING and REJECTED statuses' | [CMHandle1: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map, CMHandle2: [details:'Cm handle does not exist',status:'REJECTED'] as Map as Map] as Map || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.groovy deleted file mode 100644 index ea1b9e771..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.groovy +++ /dev/null @@ -1,87 +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.events.avcsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.spi.exceptions.DataValidationException -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class SubscriptionOutcomeMapperSpec extends Specification { - - SubscriptionOutcomeMapper objectUnderTest = Mappers.getMapper(SubscriptionOutcomeMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map subscription event response to subscription event outcome'() { - given: 'a Subscription Response Event' - def subscriptionResponseJsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, SubscriptionEventResponse.class) - when: 'the subscription response event is mapped to a subscription event outcome' - def result = objectUnderTest.toSubscriptionEventOutcome(subscriptionResponseEvent) - then: 'the resulting subscription event outcome contains expected pending targets per details grouping' - def pendingCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getPending() - assert pendingCmHandleTargetsPerDetails.get(0).getDetails() == 'No reply from DMI yet' - assert pendingCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle3', 'CMHandle4'] - and: 'the resulting subscription event outcome contains expected rejected targets per details grouping' - def rejectedCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getRejected() - assert rejectedCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error message from the DMI' - assert rejectedCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle2'] - assert rejectedCmHandleTargetsPerDetails.get(1).getDetails() == 'Some error message from the DMI' - assert rejectedCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle1'] - } - - def 'Map subscription event response with null of subscription status list to subscription event outcome causes an exception'() { - given: 'a Subscription Response Event' - def subscriptionResponseJsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, SubscriptionEventResponse.class) - and: 'set subscription status list to null' - subscriptionResponseEvent.getData().setSubscriptionStatus(subscriptionStatusList) - when: 'the subscription response event is mapped to a subscription event outcome' - objectUnderTest.toSubscriptionEventOutcome(subscriptionResponseEvent) - then: 'a DataValidationException is thrown with an expected exception details' - def exception = thrown(DataValidationException) - exception.details == 'SubscriptionStatus list cannot be null or empty' - where: 'the following values are used' - scenario || subscriptionStatusList - 'A null subscription status list' || null - 'An empty subscription status list' || new ArrayList() - } - - def 'Map subscription event response with subscription status list to subscription event outcome without any exception'() { - given: 'a Subscription Response Event' - def subscriptionResponseJsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, SubscriptionEventResponse.class) - when: 'the subscription response event is mapped to a subscription event outcome' - objectUnderTest.toSubscriptionEventOutcome(subscriptionResponseEvent) - then: 'no exception thrown' - noExceptionThrown() - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy new file mode 100644 index 000000000..b08b51ba2 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy @@ -0,0 +1,60 @@ +/* + * ============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.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class ClientCmSubscriptionNcmpInEventMapperSpec extends Specification { + + CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map clients subscription event to ncmps subscription event'() { + given: 'a Subscription Event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + when: 'the client event is mapped to a ncmp subscription event' + def result = objectUnderTest.toCmSubscriptionDmiInEvent(testEventToMap) + then: 'the resulting ncmp subscription event contains the correct clientId' + assert result.getData().getSubscription().getClientID() == "SCO-9989752" + and: 'subscription name' + assert result.getData().getSubscription().getName() == "cm-subscription-001" + and: 'is tagged value is false' + assert result.getData().getSubscription().getIsTagged() == false + and: 'data category is CM' + assert result.getData().getDataType().getDataCategory() == 'CM' + and: 'predicate targets is null' + assert result.getData().getPredicates().getTargets() == [] + and: 'datastore is passthrough-running' + assert result.getData().getPredicates().getDatastore() == 'ncmp-datastore:passthrough-running' + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy new file mode 100644 index 000000000..29defbecc --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy @@ -0,0 +1,142 @@ +/* + * ============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.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import com.hazelcast.map.IMap +import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder +import org.apache.kafka.clients.consumer.ConsumerRecord +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistenceImpl +import org.onap.cps.ncmp.api.impl.utils.SubscriptionEventResponseCloudMapper +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.spi.model.DataNodeBuilder +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec { + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) + def mockSubscriptionPersistence = Mock(SubscriptionPersistenceImpl) + def mockSubscriptionEventResponseMapper = Mock(CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper) + def mockSubscriptionEventResponseOutcome = Mock(CmSubscriptionNcmpOutEventPublisher) + def mockSubscriptionEventResponseCloudMapper = new SubscriptionEventResponseCloudMapper(new ObjectMapper()) + + def objectUnderTest = new CmSubscriptionDmiOutEventConsumer(mockForwardedSubscriptionEventCache, + mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockSubscriptionEventResponseOutcome, mockSubscriptionEventResponseCloudMapper) + + def 'Consume Subscription Event Response where all DMIs have responded'() { + given: 'a consumer record including cloud event having subscription response' + def consumerRecordWithCloudEventAndSubscriptionResponse = getConsumerRecord() + and: 'a subscription response event' + def subscriptionResponseEvent = getSubscriptionResponseEvent() + and: 'a subscription event response and notifications are enabled' + objectUnderTest.notificationFeatureEnabled = notificationEnabled + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled + and: 'subscription persistence service returns data node includes no pending cm handle' + mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [getDataNode()] + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEventResponse(consumerRecordWithCloudEventAndSubscriptionResponse) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['some-dmi-name'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> ([] as Set) + and: 'the response event is map to yang model' + numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) + and: 'the response event is persisted into the db' + numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) + and: 'the subscription event is removed from the map' + numberOfTimeToRemove * mockForwardedSubscriptionEventCache.remove('SCO-9989752cm-subscription-001') + and: 'a response outcome has been created' + numberOfTimeToResponse * mockSubscriptionEventResponseOutcome.sendResponse(subscriptionResponseEvent, 'subscriptionCreated') + where: 'the following values are used' + scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist || numberOfTimeToRemove || numberOfTimeToResponse + 'Both model loader and notification are enabled' | true | true || 1 || 1 || 1 + 'Both model loader and notification are disabled' | false | false || 0 || 0 || 0 + 'Model loader enabled and notification disabled' | true | false || 1 || 0 || 0 + 'Model loader disabled and notification enabled' | false | true || 0 || 1 || 1 + } + + def 'Consume Subscription Event Response where another DMI has not yet responded'() { + given: 'a subscription event response and notifications are enabled' + objectUnderTest.notificationFeatureEnabled = notificationEnabled + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEventResponse(getConsumerRecord()) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['responded-dmi', 'non-responded-dmi'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['non-responded-dmi'] as Set) + and: 'the response event is map to yang model' + numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) + and: 'the response event is persisted into the db' + numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) + and: 'the subscription event is removed from the map' + and: 'the subscription event is not removed from the map' + 0 * mockForwardedSubscriptionEventCache.remove(_) + and: 'a response outcome has not been created' + 0 * mockSubscriptionEventResponseOutcome.sendResponse(*_) + where: 'the following values are used' + scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist + 'Both model loader and notification are enabled' | true | true || 1 + 'Both model loader and notification are disabled' | false | false || 0 + 'Model loader enabled and notification disabled' | true | false || 1 + 'Model loader disabled and notification enabled' | false | true || 0 + } + + def getSubscriptionResponseEvent() { + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + return jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class) + } + + def getCloudEventHavingSubscriptionResponseEvent() { + return CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(getSubscriptionResponseEvent())) + .withId('some-id') + .withType('subscriptionCreated') + .withSource(URI.create('NCMP')).build() + } + + def getConsumerRecord() { + return new ConsumerRecord('topic-name', 0, 0, 'event-key', getCloudEventHavingSubscriptionResponseEvent()) + } + + def getDataNode() { + def leaves = [status:'ACCEPTED', cmHandleId:'cmhandle1'] as Map + return new DataNodeBuilder().withDataspace('NCMP-Admin') + .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') + .withLeaves(leaves).build() + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec.groovy new file mode 100644 index 000000000..df5167da9 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec.groovy @@ -0,0 +1,87 @@ +/* + * ============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.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.spi.exceptions.DataValidationException +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec extends Specification { + + CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map subscription event response to subscription event outcome'() { + given: 'a Subscription Response Event' + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class) + when: 'the subscription response event is mapped to a subscription event outcome' + def result = objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent) + then: 'the resulting subscription event outcome contains expected pending targets per details grouping' + def pendingCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getPending() + assert pendingCmHandleTargetsPerDetails.get(0).getDetails() == 'No reply from DMI yet' + assert pendingCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle3', 'CMHandle4'] + and: 'the resulting subscription event outcome contains expected rejected targets per details grouping' + def rejectedCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getRejected() + assert rejectedCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error message from the DMI' + assert rejectedCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle2'] + assert rejectedCmHandleTargetsPerDetails.get(1).getDetails() == 'Some error message from the DMI' + assert rejectedCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle1'] + } + + def 'Map subscription event response with null of subscription status list to subscription event outcome causes an exception'() { + given: 'a Subscription Response Event' + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class) + and: 'set subscription status list to null' + subscriptionResponseEvent.getData().setSubscriptionStatus(subscriptionStatusList) + when: 'the subscription response event is mapped to a subscription event outcome' + objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent) + then: 'a DataValidationException is thrown with an expected exception details' + def exception = thrown(DataValidationException) + exception.details == 'SubscriptionStatus list cannot be null or empty' + where: 'the following values are used' + scenario || subscriptionStatusList + 'A null subscription status list' || null + 'An empty subscription status list' || new ArrayList() + } + + def 'Map subscription event response with subscription status list to subscription event outcome without any exception'() { + given: 'a Subscription Response Event' + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class) + when: 'the subscription response event is mapped to a subscription event outcome' + objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent) + then: 'no exception thrown' + noExceptionThrown() + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy new file mode 100644 index 000000000..036bedb8a --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy @@ -0,0 +1,60 @@ +/* + * ============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.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec extends Specification { + + CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map subscription response event to yang model subscription event'() { + given: 'a Subscription Response Event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionDmiOutEvent.class) + when: 'the event is mapped to a yang model subscription' + def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) + then: 'the resulting yang model subscription event contains the correct clientId' + assert result.clientId == "SCO-9989752" + and: 'subscription name' + assert result.subscriptionName == "cm-subscription-001" + and: 'predicate targets cm handle size as expected' + assert result.predicates.targetCmHandles.size() == 4 + and: 'predicate targets cm handle ids as expected' + assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2", "CMHandle3", "CMHandle4"] + and: 'the status for these targets is set to expected values' + assert result.predicates.targetCmHandles.status == [SubscriptionStatus.REJECTED, SubscriptionStatus.REJECTED, SubscriptionStatus.PENDING, SubscriptionStatus.PENDING] + } + +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy new file mode 100644 index 000000000..24e829e28 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy @@ -0,0 +1,108 @@ +/* + * ============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.events.cmsubscription + +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.subscriptions.SubscriptionPersistence +import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class CmSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpec { + + def mockCmSubscriptionNcmpInEventForwarder = Mock(CmSubscriptionNcmpInEventForwarder) + def mockCmSubscriptionNcmpInEventMapper = Mock(CmSubscriptionNcmpInEventMapper) + def mockSubscriptionPersistence = Mock(SubscriptionPersistence) + def cmSubscriptionEventCloudMapper = new CmSubscriptionEventCloudMapper(new ObjectMapper()) + def objectUnderTest = new CmSubscriptionNcmpInEventConsumer(mockCmSubscriptionNcmpInEventForwarder, mockCmSubscriptionNcmpInEventMapper, mockSubscriptionPersistence, cmSubscriptionEventCloudMapper) + + def yangModelSubscriptionEvent = new YangModelSubscriptionEvent() + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + + def 'Consume, persist and forward valid CM create message'() { + given: 'an event with data category CM' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + testEventSent.getData().getDataType().setDataCategory(dataCategory) + def testCloudEventSent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(testEventSent)) + .withId('subscriptionCreated') + .withType(dataType) + .withSource(URI.create('some-resource')) + .withExtension('correlationid', 'test-cmhandle1').build() + def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) + and: 'notifications are enabled' + objectUnderTest.notificationFeatureEnabled = isNotificationEnabled + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = isModelLoaderEnabled + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(consumerRecord) + then: 'the event is mapped to a yangModelSubscription' + numberOfTimesToPersist * mockCmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent + and: 'the event is persisted' + numberOfTimesToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) + and: 'the event is forwarded' + numberOfTimesToForward * mockCmSubscriptionNcmpInEventForwarder.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreated') + where: 'given values are used' + scenario | dataCategory | dataType | isNotificationEnabled | isModelLoaderEnabled || numberOfTimesToForward || numberOfTimesToPersist + 'Both model loader and notification are enabled' | 'CM' | 'subscriptionCreated' | true | true || 1 || 1 + 'Both model loader and notification are disabled' | 'CM' | 'subscriptionCreated' | false | false || 0 || 0 + 'Model loader enabled and notification disabled' | 'CM' | 'subscriptionCreated' | false | true || 0 || 1 + 'Model loader disabled and notification enabled' | 'CM' | 'subscriptionCreated' | true | false || 1 || 0 + 'Flags are enabled but data category is FM' | 'FM' | 'subscriptionCreated' | true | true || 0 || 0 + 'Flags are enabled but data type is UPDATE' | 'CM' | 'subscriptionUpdated' | true | true || 0 || 1 + } + + def 'Consume event with wrong datastore causes an exception'() { + given: 'an event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + and: 'datastore is set to a passthrough-running datastore' + testEventSent.getData().getPredicates().setDatastore('operational') + def testCloudEventSent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(testEventSent)) + .withId('some-event-id') + .withType('some-event-type') + .withSource(URI.create('some-resource')) + .withExtension('correlationid', 'test-cmhandle1').build() + def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(consumerRecord) + then: 'an operation not supported exception is thrown' + thrown(UnsupportedOperationException) + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy new file mode 100644 index 000000000..29cf8be8b --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy @@ -0,0 +1,204 @@ +/* + * ============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.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import com.hazelcast.map.IMap +import io.cloudevents.CloudEvent +import io.cloudevents.core.CloudEventUtils +import io.cloudevents.core.data.PojoCloudEventData +import io.cloudevents.jackson.PojoCloudEventDataMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus +import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent.TargetCmHandle +import org.onap.cps.ncmp.api.inventory.InventoryPersistence +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.Data +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.util.concurrent.BlockingVariable +import java.util.concurrent.TimeUnit + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionNcmpInEventForwarder]) +class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec { + + @Autowired + CmSubscriptionNcmpInEventForwarder objectUnderTest + + @SpringBean + InventoryPersistence mockInventoryPersistence = Mock(InventoryPersistence) + @SpringBean + EventsPublisher mockSubscriptionEventPublisher = Mock(EventsPublisher) + @SpringBean + IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) + @SpringBean + CmSubscriptionEventCloudMapper subscriptionEventCloudMapper = new CmSubscriptionEventCloudMapper(new ObjectMapper()) + @SpringBean + CmSubscriptionNcmpOutEventPublisher mockCmSubscriptionNcmpOutEventPublisher = Mock(CmSubscriptionNcmpOutEventPublisher) + @SpringBean + SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) + @SpringBean + CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper = Mappers.getMapper(CmSubscriptionNcmpInEventMapper) + @SpringBean + CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper = Mappers.getMapper(CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper) + @Autowired + JsonObjectMapper jsonObjectMapper + @Autowired + ObjectMapper objectMapper + + def 'Forward valid CM create subscription and simulate timeout'() { + given: 'an event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + and: 'the InventoryPersistence returns private properties for the supplied CM Handles' + 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [ + createYangModelCmHandleWithDmiProperty(1, 1,"shape","circle"), + createYangModelCmHandleWithDmiProperty(2, 1,"shape","square") + ] + and: 'the thread creation delay is reduced to 2 seconds for testing' + objectUnderTest.dmiResponseTimeoutInMs = 2000 + and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' + def block = new BlockingVariable(5) + when: 'the valid event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreated') + then: 'An asynchronous call is made to the blocking variable' + block.get() + then: 'the event is added to the forwarded subscription event cache' + 1 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1"] as Set, 600, TimeUnit.SECONDS) + and: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' + 1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", + cloudEvent -> { + def targets = toSubscriptionEvent(cloudEvent).getData().getPredicates().getTargets() + def cmHandle2 = createCmHandle('CMHandle2', ['shape':'square'] as Map) + def cmHandle1 = createCmHandle('CMHandle1', ['shape':'circle'] as Map) + targets == [cmHandle2, cmHandle1] + } + ) + and: 'a separate thread has been created where the map is polled' + 1 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true + 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(*_) + and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' + 1 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)} + } + + def 'Forward CM create subscription where target CM Handles are #scenario'() { + given: 'an event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + and: 'the target CMHandles are set to #scenario' + testEventSent.getData().getPredicates().setTargets(invalidTargets) + when: 'the event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'some-event-type') + then: 'an operation not supported exception is thrown' + thrown(UnsupportedOperationException) + where: + scenario | invalidTargets + 'null' | null + 'empty' | [] + 'wildcard' | ['CMHandle*'] + } + + def 'Forward valid CM create subscription where targets are not associated to any existing CMHandles'() { + given: 'an event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + and: 'a subscription event response' + def emptySubscriptionEventResponse = new CmSubscriptionDmiOutEvent().withData(new Data()); + emptySubscriptionEventResponse.getData().setSubscriptionName('cm-subscription-001'); + emptySubscriptionEventResponse.getData().setClientId('SCO-9989752'); + and: 'the cm handles will be rejected' + def rejectedCmHandles = [new TargetCmHandle('CMHandle1', SubscriptionStatus.REJECTED, 'Cm handle does not exist'), + new TargetCmHandle('CMHandle2',SubscriptionStatus.REJECTED, 'Cm handle does not exist'), + new TargetCmHandle('CMHandle3',SubscriptionStatus.REJECTED, 'Cm handle does not exist')] + and: 'a yang model subscription event will be saved into the db with rejected cm handles' + def yangModelSubscriptionEvent = cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(testEventSent) + yangModelSubscriptionEvent.getPredicates().setTargetCmHandles(rejectedCmHandles) + and: 'the InventoryPersistence returns no private properties for the supplied CM Handles' + 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [] + and: 'the thread creation delay is reduced to 2 seconds for testing' + objectUnderTest.dmiResponseTimeoutInMs = 2000 + and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' + def block = new BlockingVariable(5) + when: 'the valid event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreatedStatus') + then: 'the event is not added to the forwarded subscription event cache' + 0 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1", "DMIName2"] as Set) + and: 'the event is not being forwarded with the CMHandle private properties and does not provides a valid listenable future' + 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", + cloudEvent -> { + def targets = toSubscriptionEvent(cloudEvent).getData().getPredicates().getTargets() + def cmHandle2 = createCmHandle('CMHandle2', ['shape':'square'] as Map) + def cmHandle1 = createCmHandle('CMHandle1', ['shape':'circle'] as Map) + targets == [cmHandle2, cmHandle1] + } + ) + 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", + cloudEvent -> { + def targets = toSubscriptionEvent(cloudEvent).getData().getPredicates().getTargets() + def cmHandle3 = createCmHandle('CMHandle3', ['shape':'triangle'] as Map) + targets == [cmHandle3] + } + ) + and: 'a separate thread has been created where the map is polled' + 0 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true + 0 * mockForwardedSubscriptionEventCache.get(_) + and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' + 0 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)} + and: 'the persistence service save target cm handles of the yang model subscription event as rejected ' + 1 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) + and: 'subscription outcome has been sent' + 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(emptySubscriptionEventResponse, 'subscriptionCreatedStatus') + } + + static def createYangModelCmHandleWithDmiProperty(id, dmiId,propertyName, propertyValue) { + return new YangModelCmHandle(id:"CMHandle" + id, dmiDataServiceName: "DMIName" + dmiId, dmiProperties: [new YangModelCmHandle.Property(propertyName,propertyValue)]) + } + + static def createCmHandle(id, additionalProperties) { + def cmHandle = new CmHandle(); + cmHandle.setId(id) + cmHandle.setAdditionalProperties(additionalProperties) + return cmHandle + } + + def toSubscriptionEvent(cloudEvent) { + final PojoCloudEventData deserializedCloudEvent = CloudEventUtils + .mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, + CmSubscriptionDmiInEvent.class)); + if (deserializedCloudEvent == null) { + return null; + } else { + return deserializedCloudEvent.getValue(); + } + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy new file mode 100644 index 000000000..3d034fcdc --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy @@ -0,0 +1,78 @@ +/* + * ============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.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class CmSubscriptionNcmpInEventMapperSpec extends Specification { + + CmSubscriptionNcmpInEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionNcmpInEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map subscription event to yang model subscription event where #scenario'() { + given: 'a Subscription Event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + when: 'the event is mapped to a yang model subscription' + def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) + then: 'the resulting yang model subscription event contains the correct clientId' + assert result.clientId == "SCO-9989752" + and: 'subscription name' + assert result.subscriptionName == "cm-subscription-001" + and: 'is tagged value is false' + assert !result.isTagged + and: 'predicate targets ' + assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2", "CMHandle3"] + and: 'the status for these targets is set to pending' + assert result.predicates.targetCmHandles.status == [SubscriptionStatus.PENDING, SubscriptionStatus.PENDING, SubscriptionStatus.PENDING] + and: 'the topic is null' + assert result.topic == null + } + + def 'Map empty subscription event to yang model subscription event'() { + given: 'a new Subscription Event with no data' + def testEventToMap = new CmSubscriptionNcmpInEvent() + when: 'the event is mapped to a yang model subscription' + def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) + then: 'the resulting yang model subscription event contains null clientId' + assert result.clientId == null + and: 'subscription name is null' + assert result.subscriptionName == null + and: 'is tagged value is false' + assert result.isTagged == false + and: 'predicates is null' + assert result.predicates == null + and: 'the topic is null' + assert result.topic == null + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy new file mode 100644 index 000000000..07e2e3f6a --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy @@ -0,0 +1,124 @@ +/* + * ============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.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.NcmpEventResponseCode +import org.onap.cps.ncmp.api.impl.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence +import org.onap.cps.ncmp.api.impl.utils.DataNodeBaseSpec +import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper, CmSubscriptionNcmpOutEventPublisher]) +class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec { + + @Autowired + CmSubscriptionNcmpOutEventPublisher objectUnderTest + + @SpringBean + SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) + @SpringBean + EventsPublisher mockCmSubscriptionNcmpOutEventPublisher = Mock(EventsPublisher) + @SpringBean + CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper cmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper = Mappers.getMapper(CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper) + @SpringBean + SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper = new SubscriptionOutcomeCloudMapper(new ObjectMapper()) + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + def 'Send response to the client apps successfully'() { + given: 'a subscription response event' + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class) + and: 'a subscription outcome event' + def subscriptionOutcomeJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent2.json') + def subscriptionOutcomeEvent = jsonObjectMapper.convertJsonString(subscriptionOutcomeJsonData, CmSubscriptionNcmpOutEvent.class) + and: 'a random id for the cloud event' + SubscriptionOutcomeCloudMapper.randomId = 'some-id' + and: 'a cloud event containing the outcome event' + def testCloudEventSent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(subscriptionOutcomeEvent)) + .withId('some-id') + .withType('subscriptionCreatedStatus') + .withDataSchema(URI.create('urn:cps:' + 'org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent' + ':1.0.0')) + .withExtension("correlationid", 'SCO-9989752cm-subscription-001') + .withSource(URI.create('NCMP')).build() + and: 'the persistence service return a data node that includes pending cm handles that makes it partial success' + mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [dataNode4] + when: 'the response is being sent' + objectUnderTest.sendResponse(subscriptionResponseEvent, 'subscriptionCreatedStatus') + then: 'the publisher publish the cloud event with itself and expected parameters' + 1 * mockCmSubscriptionNcmpOutEventPublisher.publishCloudEvent('subscription-response', 'SCO-9989752cm-subscription-001', testCloudEventSent) + } + + def 'Create subscription outcome message as expected'() { + given: 'a subscription response event' + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class) + and: 'a subscription outcome event' + def subscriptionOutcomeJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent.json') + def subscriptionOutcomeEvent = jsonObjectMapper.convertJsonString(subscriptionOutcomeJsonData, CmSubscriptionNcmpOutEvent.class) + and: 'a status code and status message a per #scenarios' + subscriptionOutcomeEvent.getData().setStatusCode(statusCode) + subscriptionOutcomeEvent.getData().setStatusMessage(statusMessage) + when: 'a subscription event outcome message is being formed' + def result = objectUnderTest.fromDmiOutEvent(subscriptionResponseEvent, ncmpEventResponseCode) + then: 'the result will be equal to event outcome' + result == subscriptionOutcomeEvent + where: 'the following values are used' + scenario | ncmpEventResponseCode || statusMessage || statusCode + 'is full outcome' | NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION || 'successfully applied subscription' || 1 + 'is partial outcome' | NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION || 'partially applied subscription' || 104 + } + + def 'Check cm handle id to status map to see if it is a full outcome response'() { + when: 'is full outcome response evaluated' + def response = objectUnderTest.decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap) + then: 'the result will be as expected' + response == expectedOutcomeResponseDecision + where: 'the following values are used' + scenario | cmHandleIdToStatusAndDetailsAsMap || expectedOutcomeResponseDecision + 'The map contains PENDING status' | [CMHandle1: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_PENDING + 'The map contains ACCEPTED status' | [CMHandle1: [details:'',status:'ACCEPTED'] as Map] as Map || NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION + 'The map contains REJECTED status' | [CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE + 'The map contains PENDING and PENDING statuses' | [CMHandle1: [details:'Some details',status:'PENDING'] as Map, CMHandle2: [details:'Some details',status:'PENDING'] as Map as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_PENDING + 'The map contains ACCEPTED and ACCEPTED statuses' | [CMHandle1: [details:'',status:'ACCEPTED'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map || NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION + 'The map contains REJECTED and REJECTED statuses' | [CMHandle1: [details:'Reject details',status:'REJECTED'] as Map, CMHandle2: [details:'Reject details',status:'REJECTED'] as Map as Map] as Map || NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE + 'The map contains PENDING and ACCEPTED statuses' | [CMHandle1: [details:'Some details',status:'PENDING'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION + 'The map contains REJECTED and ACCEPTED statuses' | [CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION + 'The map contains PENDING and REJECTED statuses' | [CMHandle1: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map, CMHandle2: [details:'Cm handle does not exist',status:'REJECTED'] as Map as Map] as Map || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapperSpec.groovy new file mode 100644 index 000000000..4f5d3b19d --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmSubscriptionEventCloudMapperSpec.groovy @@ -0,0 +1,115 @@ +/* + * ============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.utils + +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.core.builder.CloudEventBuilder +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class CmSubscriptionEventCloudMapperSpec extends Specification { + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + def spyObjectMapper = Spy(ObjectMapper) + + def objectUnderTest = new CmSubscriptionEventCloudMapper(spyObjectMapper) + + def 'Map the data of the cloud event to subscription event'() { + given: 'a cloud event having a subscription event in the data part' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventData = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + def testCloudEvent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(testEventData)) + .withId('some-event-id') + .withType('subscriptionCreated') + .withSource(URI.create('some-resource')) + .withExtension('correlationid', 'test-cmhandle1').build() + when: 'the cloud event map to subscription event' + def resultSubscriptionEvent = objectUnderTest.toCmSubscriptionNcmpInEvent(testCloudEvent) + then: 'the subscription event resulted having expected values' + resultSubscriptionEvent.getData() == testEventData.getData() + } + + def 'Map the null of the data of the cloud event to subscription event'() { + given: 'a cloud event having a null subscription event in the data part' + def testCloudEvent = CloudEventBuilder.v1() + .withData(null) + .withId('some-event-id') + .withType('subscriptionCreated') + .withSource(URI.create('some-resource')) + .withExtension('correlationid', 'test-cmhandle1').build() + when: 'the cloud event map to subscription event' + def resultSubscriptionEvent = objectUnderTest.toCmSubscriptionNcmpInEvent(testCloudEvent) + then: 'the subscription event resulted having a null value' + resultSubscriptionEvent == null + } + + def 'Map the subscription event to data of the cloud event'() { + given: 'a subscription event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiInEvent.json') + def testEventData = jsonObjectMapper.convertJsonString(jsonData, + CmSubscriptionDmiInEvent.class) + def testCloudEvent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(testEventData)) + .withId('some-id') + .withType('subscriptionCreated') + .withSource(URI.create('SCO-9989752')) + .withExtension('correlationid', 'test-cmhandle1').build() + when: 'the subscription event map to data of cloud event' + CmSubscriptionEventCloudMapper.randomId = 'some-id' + def resultCloudEvent = objectUnderTest.toCloudEvent(testEventData, 'some-event-key', 'subscriptionCreated') + then: 'the subscription event resulted having expected values' + resultCloudEvent.getData() == testCloudEvent.getData() + resultCloudEvent.getId() == testCloudEvent.getId() + resultCloudEvent.getType() == testCloudEvent.getType() + resultCloudEvent.getSource() == URI.create('SCO-9989752') + resultCloudEvent.getDataSchema() == URI.create('urn:cps:org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent:1.0.0') + } + + def 'Map the subscription event to cloud event with JSON processing exception'() { + given: 'a json processing exception during process' + def jsonProcessingException = new JsonProcessingException('The Cloud Event could not be constructed') + spyObjectMapper.writeValueAsBytes(_) >> { throw jsonProcessingException } + and: 'a subscription event of ncmp version' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiInEvent.json') + def testEventData = jsonObjectMapper.convertJsonString(jsonData, + CmSubscriptionDmiInEvent.class) + when: 'the subscription event map to cloud event' + def expectedResult = objectUnderTest.toCloudEvent(testEventData, 'some-key', 'some-event-type') + then: 'no exception is thrown since it has been handled already' + noExceptionThrown() + and: 'expected result should be null' + expectedResult == null + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapperSpec.groovy deleted file mode 100644 index ae6174964..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventCloudMapperSpec.groovy +++ /dev/null @@ -1,114 +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.utils - -import com.fasterxml.jackson.core.JsonProcessingException -import com.fasterxml.jackson.databind.ObjectMapper -import io.cloudevents.core.builder.CloudEventBuilder -import org.onap.cps.ncmp.events.avcsubscription1_0_0.client_to_ncmp.SubscriptionEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class SubscriptionEventCloudMapperSpec extends Specification { - - @Autowired - JsonObjectMapper jsonObjectMapper - - @Autowired - ObjectMapper objectMapper - - def spyObjectMapper = Spy(ObjectMapper) - - def objectUnderTest = new SubscriptionEventCloudMapper(spyObjectMapper) - - def 'Map the data of the cloud event to subscription event'() { - given: 'a cloud event having a subscription event in the data part' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventData = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - def testCloudEvent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(testEventData)) - .withId('some-event-id') - .withType('subscriptionCreated') - .withSource(URI.create('some-resource')) - .withExtension('correlationid', 'test-cmhandle1').build() - when: 'the cloud event map to subscription event' - def resultSubscriptionEvent = objectUnderTest.toSubscriptionEvent(testCloudEvent) - then: 'the subscription event resulted having expected values' - resultSubscriptionEvent.getData() == testEventData.getData() - } - - def 'Map the null of the data of the cloud event to subscription event'() { - given: 'a cloud event having a null subscription event in the data part' - def testCloudEvent = CloudEventBuilder.v1() - .withData(null) - .withId('some-event-id') - .withType('subscriptionCreated') - .withSource(URI.create('some-resource')) - .withExtension('correlationid', 'test-cmhandle1').build() - when: 'the cloud event map to subscription event' - def resultSubscriptionEvent = objectUnderTest.toSubscriptionEvent(testCloudEvent) - then: 'the subscription event resulted having a null value' - resultSubscriptionEvent == null - } - - def 'Map the subscription event to data of the cloud event'() { - given: 'a subscription event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEventNcmpVersion.json') - def testEventData = jsonObjectMapper.convertJsonString(jsonData, - org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent.class) - def testCloudEvent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(testEventData)) - .withId('some-id') - .withType('subscriptionCreated') - .withSource(URI.create('SCO-9989752')) - .withExtension('correlationid', 'test-cmhandle1').build() - when: 'the subscription event map to data of cloud event' - SubscriptionEventCloudMapper.randomId = 'some-id' - def resultCloudEvent = objectUnderTest.toCloudEvent(testEventData, 'some-event-key', 'subscriptionCreated') - then: 'the subscription event resulted having expected values' - resultCloudEvent.getData() == testCloudEvent.getData() - resultCloudEvent.getId() == testCloudEvent.getId() - resultCloudEvent.getType() == testCloudEvent.getType() - resultCloudEvent.getSource() == URI.create('SCO-9989752') - resultCloudEvent.getDataSchema() == URI.create('urn:cps:org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent:1.0.0') - } - - def 'Map the subscription event to cloud event with JSON processing exception'() { - given: 'a json processing exception during process' - def jsonProcessingException = new JsonProcessingException('The Cloud Event could not be constructed') - spyObjectMapper.writeValueAsBytes(_) >> { throw jsonProcessingException } - and: 'a subscription event of ncmp version' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEventNcmpVersion.json') - def testEventData = jsonObjectMapper.convertJsonString(jsonData, - org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_dmi.SubscriptionEvent.class) - when: 'the subscription event map to cloud event' - def expectedResult = objectUnderTest.toCloudEvent(testEventData, 'some-key', 'some-event-type') - then: 'no exception is thrown since it has been handled already' - noExceptionThrown() - and: 'expected result should be null' - expectedResult == null - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapperSpec.groovy index 9dcd0a645..89b13e26e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapperSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionEventResponseCloudMapperSpec.groovy @@ -22,7 +22,7 @@ package org.onap.cps.ncmp.api.impl.utils import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.core.builder.CloudEventBuilder -import org.onap.cps.ncmp.events.avcsubscription1_0_0.dmi_to_ncmp.SubscriptionEventResponse +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper import org.springframework.beans.factory.annotation.Autowired @@ -44,8 +44,8 @@ class SubscriptionEventResponseCloudMapperSpec extends Specification { def 'Map the cloud event to subscription event response'() { given: 'a cloud event having a subscription event response in the data part' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def testEventData = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEventResponse.class) + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def testEventData = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionDmiOutEvent.class) def testCloudEvent = CloudEventBuilder.v1() .withData(objectMapper.writeValueAsBytes(testEventData)) .withId('some-event-id') @@ -53,7 +53,7 @@ class SubscriptionEventResponseCloudMapperSpec extends Specification { .withSource(URI.create('some-resource')) .withExtension('correlationid', 'test-cmhandle1').build() when: 'the cloud event map to subscription event response' - def resultSubscriptionEvent = objectUnderTest.toSubscriptionEventResponse(testCloudEvent) + def resultSubscriptionEvent = objectUnderTest.toCmSubscriptionDmiOutEvent(testCloudEvent) then: 'the subscription event resulted having expected values' resultSubscriptionEvent.getData() == testEventData.getData() } @@ -67,7 +67,7 @@ class SubscriptionEventResponseCloudMapperSpec extends Specification { .withSource(URI.create('some-resource')) .withExtension('correlationid', 'test-cmhandle1').build() when: 'the cloud event map to subscription event response' - def resultSubscriptionEvent = objectUnderTest.toSubscriptionEventResponse(testCloudEvent) + def resultSubscriptionEvent = objectUnderTest.toCmSubscriptionDmiOutEvent(testCloudEvent) then: 'the subscription event response resulted having a null value' resultSubscriptionEvent == null } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapperSpec.groovy index ac055b5f6..d5670eb40 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapperSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/SubscriptionOutcomeCloudMapperSpec.groovy @@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api.impl.utils import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.core.builder.CloudEventBuilder -import org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.SubscriptionEventOutcome +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper import org.springframework.beans.factory.annotation.Autowired @@ -45,8 +45,8 @@ class SubscriptionOutcomeCloudMapperSpec extends Specification { def 'Map the subscription outcome to cloud event'() { given: 'a subscription event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionOutcomeEvent.json') - def testEventData = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEventOutcome.class) + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent.json') + def testEventData = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpOutEvent.class) def testCloudEvent = CloudEventBuilder.v1() .withData(objectMapper.writeValueAsBytes(testEventData)) .withId('some-id') @@ -61,7 +61,7 @@ class SubscriptionOutcomeCloudMapperSpec extends Specification { resultCloudEvent.getId() == testCloudEvent.getId() resultCloudEvent.getType() == testCloudEvent.getType() resultCloudEvent.getSource() == testCloudEvent.getSource() - resultCloudEvent.getDataSchema() == URI.create('urn:cps:org.onap.cps.ncmp.events.avcsubscription1_0_0.ncmp_to_client.SubscriptionEventOutcome:1.0.0') + resultCloudEvent.getDataSchema() == URI.create('urn:cps:org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent:1.0.0') } def 'Map the subscription outcome to cloud event with JSON processing exception'() { @@ -69,8 +69,8 @@ class SubscriptionOutcomeCloudMapperSpec extends Specification { def jsonProcessingException = new JsonProcessingException('The Cloud Event could not be constructed') spyObjectMapper.writeValueAsBytes(_) >> { throw jsonProcessingException } and: 'a cloud event having a subscription outcome in the data part' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionOutcomeEvent.json') - def testEventData = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEventOutcome.class) + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent.json') + def testEventData = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpOutEvent.class) when: 'the subscription outcome map to cloud event' def expectedResult = objectUnderTest.toCloudEvent(testEventData, 'some-key', 'some-event-type') then: 'no exception is thrown since it has been handled already' diff --git a/cps-ncmp-service/src/test/resources/avcSubscriptionCreationEvent.json b/cps-ncmp-service/src/test/resources/avcSubscriptionCreationEvent.json deleted file mode 100644 index 803fa48bd..000000000 --- a/cps-ncmp-service/src/test/resources/avcSubscriptionCreationEvent.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "data": { - "subscription": { - "clientID": "SCO-9989752", - "name": "cm-subscription-001" - }, - "dataType": { - "dataspace": "ALL", - "dataCategory": "CM", - "dataProvider": "CM-SERVICE" - }, - "predicates": { - "targets": [ - "CMHandle1", - "CMHandle2", - "CMHandle3" - ], - "datastore": "ncmp-datastore:passthrough-running", - "datastore-xpath-filter": "//_3gpp-nr-nrm-gnbdufunction:GNBDUFunction/_3gpp-nr-nrm-nrcelldu:NRCellDU/ | //_3gpp-nr-nrm-gnbcuupfunction:GNBCUUPFunction// | //_3gpp-nr-nrm-gnbcucpfunction:GNBCUCPFunction/_3gpp-nr-nrm-nrcelldu:NRCellCU// | //_3gpp-nr-nrm-nrsectorcarrier:NRSectorCarrier//" - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/avcSubscriptionCreationEventNcmpVersion.json b/cps-ncmp-service/src/test/resources/avcSubscriptionCreationEventNcmpVersion.json deleted file mode 100644 index f31362a1c..000000000 --- a/cps-ncmp-service/src/test/resources/avcSubscriptionCreationEventNcmpVersion.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "data": { - "subscription": { - "clientID": "SCO-9989752", - "name": "cm-subscription-001" - }, - "dataType": { - "dataspace": "ALL", - "dataCategory": "CM", - "dataProvider": "CM-SERVICE" - }, - "predicates": { - "targets":[ - { - "id":"CMHandle2", - "additional-properties":{ - "Books":"Novel" - } - }, - { - "id":"CMHandle1", - "additional-properties":{ - "Books":"Social Media" - } - } - ], - "datastore": "passthrough-running", - "datastore-xpath-filter": "//_3gpp-nr-nrm-gnbdufunction:GNBDUFunction/_3gpp-nr-nrm-nrcelldu:NRCellDU/ | //_3gpp-nr-nrm-gnbcuupfunction:GNBCUUPFunction// | //_3gpp-nr-nrm-gnbcucpfunction:GNBCUCPFunction/_3gpp-nr-nrm-nrcelldu:NRCellCU// | //_3gpp-nr-nrm-nrsectorcarrier:NRSectorCarrier//" - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/avcSubscriptionEventResponse.json b/cps-ncmp-service/src/test/resources/avcSubscriptionEventResponse.json deleted file mode 100644 index dfe8f5046..000000000 --- a/cps-ncmp-service/src/test/resources/avcSubscriptionEventResponse.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "data": { - "clientId": "SCO-9989752", - "subscriptionName": "cm-subscription-001", - "dmiName": "dminame1", - "subscriptionStatus": [ - { - "id": "CMHandle1", - "status": "REJECTED", - "details": "Some error message from the DMI" - }, - { - "id": "CMHandle2", - "status": "REJECTED", - "details": "Some other error message from the DMI" - }, - { - "id": "CMHandle3", - "status": "PENDING", - "details": "No reply from DMI yet" - }, - { - "id": "CMHandle4", - "status": "PENDING", - "details": "No reply from DMI yet" - } - ] - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent.json b/cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent.json deleted file mode 100644 index 14e8cbb4c..000000000 --- a/cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "data": { - "statusCode": 104, - "statusMessage": "partially applied subscription", - "additionalInfo": { - "rejected": [ - { - "details": "Some other error message from the DMI", - "targets": ["CMHandle2"] - }, - { - "details": "Some error message from the DMI", - "targets": ["CMHandle1"] - } - ], - "pending": [ - { - "details": "No reply from DMI yet", - "targets": ["CMHandle3", "CMHandle4"] - } - ] - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent2.json b/cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent2.json deleted file mode 100644 index 35ff0241d..000000000 --- a/cps-ncmp-service/src/test/resources/avcSubscriptionOutcomeEvent2.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "data": { - "statusCode": 104, - "statusMessage": "partially applied subscription", - "additionalInfo": { - "rejected": [ - { - "details": "Cm handle does not exist", - "targets": ["CMHandle1"] - } - ], - "pending": [ - { - "details": "Subscription forwarded to dmi plugin", - "targets": ["CMHandle3"] - } - ] - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionDmiInEvent.json b/cps-ncmp-service/src/test/resources/cmSubscriptionDmiInEvent.json new file mode 100644 index 000000000..f31362a1c --- /dev/null +++ b/cps-ncmp-service/src/test/resources/cmSubscriptionDmiInEvent.json @@ -0,0 +1,31 @@ +{ + "data": { + "subscription": { + "clientID": "SCO-9989752", + "name": "cm-subscription-001" + }, + "dataType": { + "dataspace": "ALL", + "dataCategory": "CM", + "dataProvider": "CM-SERVICE" + }, + "predicates": { + "targets":[ + { + "id":"CMHandle2", + "additional-properties":{ + "Books":"Novel" + } + }, + { + "id":"CMHandle1", + "additional-properties":{ + "Books":"Social Media" + } + } + ], + "datastore": "passthrough-running", + "datastore-xpath-filter": "//_3gpp-nr-nrm-gnbdufunction:GNBDUFunction/_3gpp-nr-nrm-nrcelldu:NRCellDU/ | //_3gpp-nr-nrm-gnbcuupfunction:GNBCUUPFunction// | //_3gpp-nr-nrm-gnbcucpfunction:GNBCUCPFunction/_3gpp-nr-nrm-nrcelldu:NRCellCU// | //_3gpp-nr-nrm-nrsectorcarrier:NRSectorCarrier//" + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json b/cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json new file mode 100644 index 000000000..dfe8f5046 --- /dev/null +++ b/cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json @@ -0,0 +1,29 @@ +{ + "data": { + "clientId": "SCO-9989752", + "subscriptionName": "cm-subscription-001", + "dmiName": "dminame1", + "subscriptionStatus": [ + { + "id": "CMHandle1", + "status": "REJECTED", + "details": "Some error message from the DMI" + }, + { + "id": "CMHandle2", + "status": "REJECTED", + "details": "Some other error message from the DMI" + }, + { + "id": "CMHandle3", + "status": "PENDING", + "details": "No reply from DMI yet" + }, + { + "id": "CMHandle4", + "status": "PENDING", + "details": "No reply from DMI yet" + } + ] + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpInEvent.json b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpInEvent.json new file mode 100644 index 000000000..803fa48bd --- /dev/null +++ b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpInEvent.json @@ -0,0 +1,22 @@ +{ + "data": { + "subscription": { + "clientID": "SCO-9989752", + "name": "cm-subscription-001" + }, + "dataType": { + "dataspace": "ALL", + "dataCategory": "CM", + "dataProvider": "CM-SERVICE" + }, + "predicates": { + "targets": [ + "CMHandle1", + "CMHandle2", + "CMHandle3" + ], + "datastore": "ncmp-datastore:passthrough-running", + "datastore-xpath-filter": "//_3gpp-nr-nrm-gnbdufunction:GNBDUFunction/_3gpp-nr-nrm-nrcelldu:NRCellDU/ | //_3gpp-nr-nrm-gnbcuupfunction:GNBCUUPFunction// | //_3gpp-nr-nrm-gnbcucpfunction:GNBCUCPFunction/_3gpp-nr-nrm-nrcelldu:NRCellCU// | //_3gpp-nr-nrm-nrsectorcarrier:NRSectorCarrier//" + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json new file mode 100644 index 000000000..14e8cbb4c --- /dev/null +++ b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json @@ -0,0 +1,24 @@ +{ + "data": { + "statusCode": 104, + "statusMessage": "partially applied subscription", + "additionalInfo": { + "rejected": [ + { + "details": "Some other error message from the DMI", + "targets": ["CMHandle2"] + }, + { + "details": "Some error message from the DMI", + "targets": ["CMHandle1"] + } + ], + "pending": [ + { + "details": "No reply from DMI yet", + "targets": ["CMHandle3", "CMHandle4"] + } + ] + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent2.json b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent2.json new file mode 100644 index 000000000..35ff0241d --- /dev/null +++ b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent2.json @@ -0,0 +1,20 @@ +{ + "data": { + "statusCode": 104, + "statusMessage": "partially applied subscription", + "additionalInfo": { + "rejected": [ + { + "details": "Cm handle does not exist", + "targets": ["CMHandle1"] + } + ], + "pending": [ + { + "details": "Subscription forwarded to dmi plugin", + "targets": ["CMHandle3"] + } + ] + } + } +} \ No newline at end of file -- cgit 1.2.3-korg