From 3266576dab0fb3b564b2066bdc67b404b3477daa Mon Sep 17 00:00:00 2001 From: "raviteja.karumuri" Date: Wed, 12 Apr 2023 16:25:19 +0100 Subject: [CPS] Re-structuring the packages for better understanding Issue-ID: CPS-1557 Signed-off-by: raviteja.karumuri Change-Id: I16be74808eea6e3ce24574ae24ce082063bd0de9 --- .../api/impl/NetworkCmProxyDataServiceImpl.java | 2 +- .../cps/ncmp/api/impl/event/EventsPublisher.java | 66 ------ .../impl/event/avc/SubscriptionEventConsumer.java | 88 -------- .../impl/event/avc/SubscriptionEventForwarder.java | 106 ---------- .../impl/event/avc/SubscriptionEventMapper.java | 47 ----- .../cps/ncmp/api/impl/event/lcm/LcmEventType.java | 38 ---- .../event/lcm/LcmEventsCmHandleStateHandler.java | 58 ------ .../lcm/LcmEventsCmHandleStateHandlerImpl.java | 227 --------------------- .../ncmp/api/impl/event/lcm/LcmEventsCreator.java | 100 --------- .../api/impl/event/lcm/LcmEventsCreatorHelper.java | 227 --------------------- .../ncmp/api/impl/event/lcm/LcmEventsService.java | 68 ------ .../cps/ncmp/api/impl/events/EventsPublisher.java | 66 ++++++ .../ncmp/api/impl/events/avc/AvcEventConsumer.java | 53 +++++ .../ncmp/api/impl/events/avc/AvcEventMapper.java | 44 ++++ .../ncmp/api/impl/events/avc/AvcEventProducer.java | 56 +++++ .../avcsubscription/SubscriptionEventConsumer.java | 88 ++++++++ .../SubscriptionEventForwarder.java | 106 ++++++++++ .../avcsubscription/SubscriptionEventMapper.java | 47 +++++ .../cps/ncmp/api/impl/events/lcm/LcmEventType.java | 38 ++++ .../events/lcm/LcmEventsCmHandleStateHandler.java | 58 ++++++ .../lcm/LcmEventsCmHandleStateHandlerImpl.java | 227 +++++++++++++++++++++ .../ncmp/api/impl/events/lcm/LcmEventsCreator.java | 100 +++++++++ .../impl/events/lcm/LcmEventsCreatorHelper.java | 227 +++++++++++++++++++++ .../ncmp/api/impl/events/lcm/LcmEventsService.java | 68 ++++++ .../impl/notifications/avc/AvcEventConsumer.java | 53 ----- .../api/impl/notifications/avc/AvcEventMapper.java | 44 ---- .../impl/notifications/avc/AvcEventProducer.java | 56 ----- .../ncmp/api/inventory/sync/ModuleSyncTasks.java | 2 +- ...rkCmProxyDataServiceImplRegistrationSpec.groovy | 2 +- .../impl/NetworkCmProxyDataServiceImplSpec.groovy | 2 +- .../event/avc/SubscriptionEventConsumerSpec.groovy | 113 ---------- .../avc/SubscriptionEventForwarderSpec.groovy | 96 --------- .../LcmEventsCmHandleStateHandlerImplSpec.groovy | 211 ------------------- .../api/impl/event/lcm/LcmEventsCreatorSpec.groovy | 162 --------------- .../impl/event/lcm/LcmEventsPublisherSpec.groovy | 83 -------- .../api/impl/event/lcm/LcmEventsServiceSpec.groovy | 63 ------ .../avc/AvcEventProducerIntegrationSpec.groovy | 84 ++++++++ .../avc/SubscriptionCreateProducerDemo.groovy | 57 ++++++ .../events/avc/SubscriptionEventMapperSpec.groovy | 63 ++++++ .../SubscriptionEventConsumerSpec.groovy | 113 ++++++++++ .../SubscriptionEventForwarderSpec.groovy | 94 +++++++++ .../LcmEventsCmHandleStateHandlerImplSpec.groovy | 211 +++++++++++++++++++ .../impl/events/lcm/LcmEventsCreatorSpec.groovy | 162 +++++++++++++++ .../impl/events/lcm/LcmEventsPublisherSpec.groovy | 83 ++++++++ .../impl/events/lcm/LcmEventsServiceSpec.groovy | 63 ++++++ .../avc/AvcEventProducerIntegrationSpec.groovy | 85 -------- .../avc/SubscriptionCreateProducerDemo.groovy | 57 ------ .../avc/SubscriptionEventMapperSpec.groovy | 63 ------ .../api/inventory/sync/ModuleSyncTasksSpec.groovy | 4 +- 49 files changed, 2114 insertions(+), 2117 deletions(-) delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/EventsPublisher.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventForwarder.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventType.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandler.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreator.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorHelper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsService.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/EventsPublisher.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventForwarderSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsPublisherSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsServiceSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducerIntegrationSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionCreateProducerDemo.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionCreateProducerDemo.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionEventMapperSpec.groovy (limited to 'cps-ncmp-service') diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index d3a4f530f..b3904bd0b 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -44,7 +44,7 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; -import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler; +import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; import org.onap.cps.ncmp.api.impl.operations.DmiOperations; import org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/EventsPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/EventsPublisher.java deleted file mode 100644 index 60d39db7a..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/EventsPublisher.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 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.event; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.kafka.support.SendResult; -import org.springframework.stereotype.Service; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.ListenableFutureCallback; - -/** - * EventsPublisher to publish events. - */ - -@Slf4j -@Service -@RequiredArgsConstructor -public class EventsPublisher { - - private final KafkaTemplate eventKafkaTemplate; - - /** - * LCM Event publisher. - * - * @param topicName valid topic name - * @param eventKey message key - * @param event message payload - */ - public void publishEvent(final String topicName, final String eventKey, final T event) { - final ListenableFuture> eventFuture = - eventKafkaTemplate.send(topicName, eventKey, event); - - eventFuture.addCallback(new ListenableFutureCallback<>() { - @Override - public void onFailure(final Throwable throwable) { - log.error("Unable to publish event to topic : {} due to {}", topicName, throwable.getMessage()); - } - - @Override - public void onSuccess(final SendResult sendResult) { - log.debug("Successfully published event to topic : {} , Event : {}", - sendResult.getRecordMetadata().topic(), sendResult.getProducerRecord().value()); - } - }); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumer.java deleted file mode 100644 index 2685ce4ca..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumer.java +++ /dev/null @@ -1,88 +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.event.avc; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.event.model.InnerSubscriptionEvent; -import org.onap.cps.ncmp.event.model.SubscriptionEvent; -import org.onap.cps.spi.exceptions.OperationNotYetSupportedException; -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; - - @Value("${notification.enabled:true}") - private boolean notificationFeatureEnabled; - - @Value("${ncmp.model-loader.subscription:false}") - private boolean subscriptionModelLoaderEnabled; - - /** - * Consume the specified event. - * - * @param subscriptionEvent the event to be consumed - */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-topic}", - properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.SubscriptionEvent"}) - public void consumeSubscriptionEvent(final SubscriptionEvent subscriptionEvent) { - final InnerSubscriptionEvent event = subscriptionEvent.getEvent(); - final String eventDatastore = event.getPredicates().getDatastore(); - if (!(eventDatastore.equals("passthrough-running") || eventDatastore.equals("passthrough-operational"))) { - throw new OperationNotYetSupportedException( - "passthrough datastores are currently only supported for event subscriptions"); - } - if ("CM".equals(event.getDataType().getDataCategory())) { - log.debug("Consuming event {} ...", subscriptionEvent); - if (subscriptionModelLoaderEnabled) { - persistSubscriptionEvent(subscriptionEvent); - } - if ("CREATE".equals(subscriptionEvent.getEventType().value())) { - log.info("Subscription for ClientID {} with name {} ...", - event.getSubscription().getClientID(), - event.getSubscription().getName()); - if (notificationFeatureEnabled) { - subscriptionEventForwarder.forwardCreateSubscriptionEvent(subscriptionEvent); - } - } - } 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/event/avc/SubscriptionEventForwarder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventForwarder.java deleted file mode 100644 index 635059bfe..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventForwarder.java +++ /dev/null @@ -1,106 +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.event.avc; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.event.EventsPublisher; -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; -import org.onap.cps.ncmp.api.inventory.InventoryPersistence; -import org.onap.cps.ncmp.event.model.SubscriptionEvent; -import org.onap.cps.spi.exceptions.OperationNotYetSupportedException; -import org.springframework.stereotype.Component; - - -@Component -@Slf4j -@RequiredArgsConstructor -public class SubscriptionEventForwarder { - - private final InventoryPersistence inventoryPersistence; - private final EventsPublisher eventsPublisher; - - private static final String DMI_AVC_SUBSCRIPTION_TOPIC_PREFIX = "ncmp-dmi-cm-avc-subscription-"; - - /** - * Forward subscription event. - * - * @param subscriptionEvent the event to be forwarded - */ - public void forwardCreateSubscriptionEvent(final SubscriptionEvent subscriptionEvent) { - final List cmHandleTargets = subscriptionEvent.getEvent().getPredicates().getTargets(); - if (cmHandleTargets == null || cmHandleTargets.isEmpty() - || cmHandleTargets.stream().anyMatch(id -> ((String) id).contains("*"))) { - throw new OperationNotYetSupportedException( - "CMHandle targets are required. \"Wildcard\" operations are not yet supported"); - } - final List cmHandleTargetsAsStrings = cmHandleTargets.stream().map( - Objects::toString).collect(Collectors.toList()); - final Collection yangModelCmHandles = - inventoryPersistence.getYangModelCmHandles(cmHandleTargetsAsStrings); - final Map>> dmiNameCmHandleMap = - organizeByDmiName(yangModelCmHandles); - dmiNameCmHandleMap.forEach((dmiName, cmHandlePropertiesMap) -> { - subscriptionEvent.getEvent().getPredicates().setTargets(Collections.singletonList(cmHandlePropertiesMap)); - final String eventKey = createEventKey(subscriptionEvent, dmiName); - eventsPublisher.publishEvent(DMI_AVC_SUBSCRIPTION_TOPIC_PREFIX + dmiName, eventKey, subscriptionEvent); - }); - } - - private Map>> organizeByDmiName( - final Collection yangModelCmHandles) { - final Map>> dmiNameCmHandlePropertiesMap = new HashMap<>(); - yangModelCmHandles.forEach(cmHandle -> { - final String dmiName = cmHandle.resolveDmiServiceName(RequiredDmiService.DATA); - if (!dmiNameCmHandlePropertiesMap.containsKey(dmiName)) { - final Map> cmHandleDmiPropertiesMap = new HashMap<>(); - cmHandleDmiPropertiesMap.put(cmHandle.getId(), dmiPropertiesAsMap(cmHandle)); - dmiNameCmHandlePropertiesMap.put(cmHandle.getDmiDataServiceName(), cmHandleDmiPropertiesMap); - } else { - dmiNameCmHandlePropertiesMap.get(cmHandle.getDmiDataServiceName()) - .put(cmHandle.getId(), dmiPropertiesAsMap(cmHandle)); - } - }); - return dmiNameCmHandlePropertiesMap; - } - - private String createEventKey(final SubscriptionEvent subscriptionEvent, final String dmiName) { - return subscriptionEvent.getEvent().getSubscription().getClientID() - + "-" - + subscriptionEvent.getEvent().getSubscription().getName() - + "-" - + dmiName; - } - - public Map dmiPropertiesAsMap(final YangModelCmHandle yangModelCmHandle) { - return yangModelCmHandle.getDmiProperties().stream().collect( - Collectors.toMap(YangModelCmHandle.Property::getName, YangModelCmHandle.Property::getValue)); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventMapper.java deleted file mode 100644 index e18448d1f..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventMapper.java +++ /dev/null @@ -1,47 +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.event.avc; - -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.event.model.SubscriptionEvent; - -@Mapper(componentModel = "spring") -public interface SubscriptionEventMapper { - - @Mapping(source = "event.subscription.clientID", target = "clientId") - @Mapping(source = "event.subscription.name", target = "subscriptionName") - @Mapping(source = "event.subscription.isTagged", target = "tagged") - @Mapping(source = "event.predicates.targets", - target = "predicates.targetCmHandles", qualifiedByName = "mapTargetsToCmHandleTargets") - @Mapping(source = "event.predicates.datastore", target = "predicates.datastore") - YangModelSubscriptionEvent toYangModelSubscriptionEvent(SubscriptionEvent subscriptionEvent); - - @Named("mapTargetsToCmHandleTargets") - default List mapTargetsToCmHandleTargets(List targets) { - return targets.stream().map( - target -> new YangModelSubscriptionEvent.TargetCmHandle(target.toString())).collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventType.java deleted file mode 100644 index f793dedb8..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventType.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 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.event.lcm; - -public enum LcmEventType { - - CREATE("create"), UPDATE("update"), DELETE("delete"); - - private final String eventName; - - private final String eventTypeTemplate = "org.onap.ncmp.cmhandle-lcm-event.%s"; - - LcmEventType(final String eventName) { - this.eventName = String.format(eventTypeTemplate, eventName); - } - - public String getEventType() { - return this.eventName; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandler.java deleted file mode 100644 index 5ff2afa5e..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 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.event.lcm; - -import java.util.Map; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; -import org.onap.cps.ncmp.api.inventory.CmHandleState; -import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; - -/** - * The implementation of it should handle the persisting of composite state and delegate the request to publish the - * corresponding lcm event. - */ -public interface LcmEventsCmHandleStateHandler { - - /** - * Updates the composite state of cmHandle based on cmHandleState. - * - * @param yangModelCmHandle cm handle represented as yang model - * @param targetCmHandleState target cm handle state - */ - void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState); - - /** - * Updates the composite state of cmHandle based on cmHandleState in batch. - * - * @param cmHandleStatePerCmHandle Map of Yang Model Cm Handle and corresponding cm handle state. - */ - void updateCmHandleStateBatch(final Map cmHandleStatePerCmHandle); - - /** - * Publish LCM Event. - * - * @param targetNcmpServiceCmHandle target NcmpServiceCmHandle - * @param currentNcmpServiceCmHandle current NcmpServiceCmHandle - */ - void publishLcmEventAsynchronously(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle currentNcmpServiceCmHandle); - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java deleted file mode 100644 index 6485fdf76..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java +++ /dev/null @@ -1,227 +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.event.lcm; - -import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED; -import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED; -import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED; -import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY; - -import io.micrometer.core.annotation.Timed; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; -import org.onap.cps.ncmp.api.inventory.CmHandleState; -import org.onap.cps.ncmp.api.inventory.CompositeState; -import org.onap.cps.ncmp.api.inventory.CompositeStateUtils; -import org.onap.cps.ncmp.api.inventory.InventoryPersistence; -import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; -import org.onap.ncmp.cmhandle.event.lcm.LcmEvent; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor -public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleStateHandler { - - private final InventoryPersistence inventoryPersistence; - private final LcmEventsCreator lcmEventsCreator; - private final LcmEventsService lcmEventsService; - - @Override - public void updateCmHandleState(final YangModelCmHandle updatedYangModelCmHandle, - final CmHandleState targetCmHandleState) { - - final CompositeState compositeState = updatedYangModelCmHandle.getCompositeState(); - - if (isCompositeStateSame(compositeState, targetCmHandleState)) { - log.debug("CmHandle with id : {} already in state : {}", updatedYangModelCmHandle.getId(), - targetCmHandleState); - } else { - final YangModelCmHandle currentYangModelCmHandle = YangModelCmHandle.deepCopyOf(updatedYangModelCmHandle); - updateToSpecifiedCmHandleState(updatedYangModelCmHandle, targetCmHandleState); - persistCmHandle(updatedYangModelCmHandle, currentYangModelCmHandle); - publishLcmEventAsynchronously(toNcmpServiceCmHandle(updatedYangModelCmHandle), - toNcmpServiceCmHandle(currentYangModelCmHandle)); - } - } - - @Override - @Timed(value = "cps.ncmp.cmhandle.state.update.batch", - description = "Time taken to update a batch of cm handle states") - public void updateCmHandleStateBatch(final Map cmHandleStatePerCmHandle) { - final Collection cmHandleTransitionPairs = - prepareCmHandleTransitionBatch(cmHandleStatePerCmHandle); - persistCmHandleBatch(cmHandleTransitionPairs); - publishLcmEventBatchAsynchronously(cmHandleTransitionPairs); - } - - @Async("notificationExecutor") - @Override - public void publishLcmEventAsynchronously(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle currentNcmpServiceCmHandle) { - publishLcmEvent(targetNcmpServiceCmHandle, currentNcmpServiceCmHandle); - } - - /** - * Publish LcmEvent in batches and in asynchronous manner. - * - * @param cmHandleTransitionPairs Pair of existing and modified cm handle represented as YangModelCmHandle - */ - @Async("notificationExecutor") - public void publishLcmEventBatchAsynchronously(final Collection cmHandleTransitionPairs) { - cmHandleTransitionPairs.forEach(cmHandleTransitionPair -> publishLcmEvent( - toNcmpServiceCmHandle(cmHandleTransitionPair.getTargetYangModelCmHandle()), - toNcmpServiceCmHandle(cmHandleTransitionPair.getCurrentYangModelCmHandle()))); - } - - private void publishLcmEvent(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - final String cmHandleId = targetNcmpServiceCmHandle.getCmHandleId(); - final LcmEvent lcmEvent = - lcmEventsCreator.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - lcmEventsService.publishLcmEvent(cmHandleId, lcmEvent); - } - - private Collection prepareCmHandleTransitionBatch( - final Map cmHandleStatePerCmHandle) { - final List cmHandleTransitionPairs = new ArrayList<>(cmHandleStatePerCmHandle.size()); - cmHandleStatePerCmHandle.forEach((yangModelCmHandle, targetCmHandleState) -> { - - final CompositeState compositeState = yangModelCmHandle.getCompositeState(); - - if (isCompositeStateSame(compositeState, targetCmHandleState)) { - log.debug("CmHandle with id : {} already in state : {}", yangModelCmHandle.getId(), - targetCmHandleState); - } else { - final CmHandleTransitionPair cmHandleTransitionPair = new CmHandleTransitionPair(); - cmHandleTransitionPair.setCurrentYangModelCmHandle(YangModelCmHandle.deepCopyOf(yangModelCmHandle)); - updateToSpecifiedCmHandleState(yangModelCmHandle, targetCmHandleState); - cmHandleTransitionPair.setTargetYangModelCmHandle(yangModelCmHandle); - cmHandleTransitionPairs.add(cmHandleTransitionPair); - } - }); - - return cmHandleTransitionPairs; - } - - - private void persistCmHandle(final YangModelCmHandle targetYangModelCmHandle, - final YangModelCmHandle currentYangModelCmHandle) { - if (isNew(currentYangModelCmHandle.getCompositeState(), targetYangModelCmHandle.getCompositeState())) { - log.debug("Registering a new cm handle {}", targetYangModelCmHandle.getId()); - inventoryPersistence.saveCmHandle(targetYangModelCmHandle); - } else if (isDeleted(targetYangModelCmHandle.getCompositeState())) { - log.info("CmHandle with Id : {} is DELETED", targetYangModelCmHandle.getId()); - } else { - inventoryPersistence.saveCmHandleState(targetYangModelCmHandle.getId(), - targetYangModelCmHandle.getCompositeState()); - } - } - - private void persistCmHandleBatch(final Collection cmHandleTransitionPairs) { - - final List newCmHandles = new ArrayList<>(); - final Map compositeStatePerCmHandleId = new LinkedHashMap<>(); - - cmHandleTransitionPairs.forEach(cmHandleTransitionPair -> { - if (isNew(cmHandleTransitionPair.getCurrentYangModelCmHandle().getCompositeState(), - cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState())) { - newCmHandles.add(cmHandleTransitionPair.getTargetYangModelCmHandle()); - } else if (!isDeleted(cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState())) { - compositeStatePerCmHandleId.put(cmHandleTransitionPair.getTargetYangModelCmHandle().getId(), - cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState()); - } - }); - - inventoryPersistence.saveCmHandleBatch(newCmHandles); - inventoryPersistence.saveCmHandleStateBatch(compositeStatePerCmHandleId); - - } - - private void updateToSpecifiedCmHandleState(final YangModelCmHandle yangModelCmHandle, - final CmHandleState targetCmHandleState) { - - if (READY == targetCmHandleState) { - setInitialStates(yangModelCmHandle); - } else if (ADVISED == targetCmHandleState) { - if (yangModelCmHandle.getCompositeState() == null) { - registerNewCmHandle(yangModelCmHandle); - } else if (yangModelCmHandle.getCompositeState().getCmHandleState() == LOCKED) { - retryCmHandle(yangModelCmHandle); - } - } else { - setCmHandleState(yangModelCmHandle, targetCmHandleState); - } - } - - private void setInitialStates(final YangModelCmHandle yangModelCmHandle) { - CompositeStateUtils.setInitialDataStoreSyncState().accept(yangModelCmHandle.getCompositeState()); - CompositeStateUtils.setCompositeState(READY).accept(yangModelCmHandle.getCompositeState()); - } - - private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) { - CompositeStateUtils.setCompositeStateForRetry().accept(yangModelCmHandle.getCompositeState()); - } - - private void registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) { - yangModelCmHandle.setCompositeState(new CompositeState()); - setCmHandleState(yangModelCmHandle, ADVISED); - } - - private void setCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState) { - CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState()); - } - - private boolean isNew(final CompositeState existingCompositeState, final CompositeState targetCompositeState) { - return (existingCompositeState == null && targetCompositeState.getCmHandleState() == ADVISED); - } - - private boolean isDeleted(final CompositeState targetCompositeState) { - return targetCompositeState.getCmHandleState() == DELETED; - } - - private boolean isCompositeStateSame(final CompositeState compositeState, final CmHandleState targetCmHandleState) { - return (compositeState != null && compositeState.getCmHandleState() == targetCmHandleState); - } - - private NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) { - return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle); - } - - @Getter - @Setter - @NoArgsConstructor - static class CmHandleTransitionPair { - private YangModelCmHandle currentYangModelCmHandle; - private YangModelCmHandle targetYangModelCmHandle; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreator.java deleted file mode 100644 index aef1ed9bd..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreator.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 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.event.lcm; - -import java.util.UUID; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter; -import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; -import org.onap.ncmp.cmhandle.event.lcm.Event; -import org.onap.ncmp.cmhandle.event.lcm.LcmEvent; -import org.onap.ncmp.cmhandle.event.lcm.Values; -import org.springframework.stereotype.Component; - - -/** - * LcmEventsCreator to create LcmEvent based on relevant operation. - */ -@Slf4j -@Component -public class LcmEventsCreator { - - /** - * Populate Lifecycle Management Event. - * - * @param cmHandleId cm handle identifier - * @param targetNcmpServiceCmHandle target ncmp service cmhandle - * @param existingNcmpServiceCmHandle existing ncmp service cmhandle - * @return Populated LcmEvent - */ - public LcmEvent populateLcmEvent(final String cmHandleId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - return createLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - } - - private LcmEvent createLcmEvent(final String cmHandleId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - final LcmEventType lcmEventType = - LcmEventsCreatorHelper.determineEventType(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - final LcmEvent lcmEvent = lcmEventHeader(cmHandleId, lcmEventType); - lcmEvent.setEvent( - lcmEventPayload(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, lcmEventType)); - return lcmEvent; - } - - private Event lcmEventPayload(final String eventCorrelationId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle, final LcmEventType lcmEventType) { - final Event event = new Event(); - event.setCmHandleId(eventCorrelationId); - final CmHandleValuesHolder cmHandleValuesHolder = - LcmEventsCreatorHelper.determineEventValues(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, - lcmEventType); - event.setOldValues(cmHandleValuesHolder.getOldValues()); - event.setNewValues(cmHandleValuesHolder.getNewValues()); - - return event; - } - - private LcmEvent lcmEventHeader(final String eventCorrelationId, final LcmEventType lcmEventType) { - final LcmEvent lcmEvent = new LcmEvent(); - lcmEvent.setEventId(UUID.randomUUID().toString()); - lcmEvent.setEventCorrelationId(eventCorrelationId); - lcmEvent.setEventTime(EventDateTimeFormatter.getCurrentDateTime()); - lcmEvent.setEventSource("org.onap.ncmp"); - lcmEvent.setEventType(lcmEventType.getEventType()); - lcmEvent.setEventSchema("org.onap.ncmp:cmhandle-lcm-event"); - lcmEvent.setEventSchemaVersion("1.0"); - return lcmEvent; - } - - @NoArgsConstructor - @Getter - @Setter - static class CmHandleValuesHolder { - - private Values oldValues; - private Values newValues; - } - -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorHelper.java deleted file mode 100644 index 852323df7..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorHelper.java +++ /dev/null @@ -1,227 +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.event.lcm; - -import static org.onap.cps.ncmp.api.impl.event.lcm.LcmEventType.CREATE; -import static org.onap.cps.ncmp.api.impl.event.lcm.LcmEventType.DELETE; -import static org.onap.cps.ncmp.api.impl.event.lcm.LcmEventType.UPDATE; -import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED; - -import com.google.common.collect.MapDifference; -import com.google.common.collect.Maps; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; -import org.onap.ncmp.cmhandle.event.lcm.Values; - -/** - * LcmEventsCreatorHelper has helper methods to create LcmEvent. - * Determine the lcm event type i.e create,update and delete. - * Based on lcm event type create the LcmEvent payload. - */ -@Slf4j -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class LcmEventsCreatorHelper { - - /** - * Determining the event type based on the composite state. - * - * @param targetNcmpServiceCmHandle target ncmpServiceCmHandle - * @param existingNcmpServiceCmHandle existing ncmpServiceCmHandle - * @return Event Type - */ - public static LcmEventType determineEventType(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - - if (existingNcmpServiceCmHandle.getCompositeState() == null) { - return CREATE; - } else if (targetNcmpServiceCmHandle.getCompositeState().getCmHandleState() == DELETED) { - return DELETE; - } - return UPDATE; - } - - /** - * Determine the cmhandle value difference pair.Contains the difference in the form of oldValues and newValues. - * - * @param targetNcmpServiceCmHandle target ncmpServiceCmHandle - * @param existingNcmpServiceCmHandle existing ncmpServiceCmHandle - * @param lcmEventType lcm event type - * @return Lcm Event Value difference pair - */ - public static LcmEventsCreator.CmHandleValuesHolder determineEventValues( - final NcmpServiceCmHandle targetNcmpServiceCmHandle, final NcmpServiceCmHandle existingNcmpServiceCmHandle, - final LcmEventType lcmEventType) { - - if (CREATE == lcmEventType) { - return determineCreateEventValues(targetNcmpServiceCmHandle); - } else if (UPDATE == lcmEventType) { - return determineUpdateEventValues(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - } - return new LcmEventsCreator.CmHandleValuesHolder(); - - } - - private static LcmEventsCreator.CmHandleValuesHolder determineCreateEventValues( - final NcmpServiceCmHandle ncmpServiceCmHandle) { - final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder = new LcmEventsCreator.CmHandleValuesHolder(); - cmHandleValuesHolder.setNewValues(new Values()); - cmHandleValuesHolder.getNewValues().setDataSyncEnabled(getDataSyncEnabledFlag(ncmpServiceCmHandle)); - cmHandleValuesHolder.getNewValues() - .setCmHandleState(mapCmHandleStateToLcmEventCmHandleState(ncmpServiceCmHandle)); - cmHandleValuesHolder.getNewValues().setCmHandleProperties(List.of(ncmpServiceCmHandle.getPublicProperties())); - return cmHandleValuesHolder; - } - - private static LcmEventsCreator.CmHandleValuesHolder determineUpdateEventValues( - final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - - final boolean hasDataSyncFlagEnabledChanged = - hasDataSyncEnabledFlagChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - final boolean hasCmHandleStateChanged = - hasCmHandleStateChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - final boolean arePublicCmHandlePropertiesEqual = - arePublicCmHandlePropertiesEqual(targetNcmpServiceCmHandle.getPublicProperties(), - existingNcmpServiceCmHandle.getPublicProperties()); - - final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder = new LcmEventsCreator.CmHandleValuesHolder(); - - if (hasDataSyncFlagEnabledChanged || hasCmHandleStateChanged || (!arePublicCmHandlePropertiesEqual)) { - cmHandleValuesHolder.setOldValues(new Values()); - cmHandleValuesHolder.setNewValues(new Values()); - } else { - return cmHandleValuesHolder; - } - - if (hasDataSyncFlagEnabledChanged) { - setDataSyncEnabledFlag(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, cmHandleValuesHolder); - } - - if (hasCmHandleStateChanged) { - setCmHandleStateChange(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, cmHandleValuesHolder); - } - - if (!arePublicCmHandlePropertiesEqual) { - setPublicCmHandlePropertiesChange(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, - cmHandleValuesHolder); - } - - return cmHandleValuesHolder; - - } - - private static void setDataSyncEnabledFlag(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle, - final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder) { - - cmHandleValuesHolder.getOldValues().setDataSyncEnabled(getDataSyncEnabledFlag(existingNcmpServiceCmHandle)); - cmHandleValuesHolder.getNewValues().setDataSyncEnabled(getDataSyncEnabledFlag(targetNcmpServiceCmHandle)); - - } - - private static void setCmHandleStateChange(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle, - final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder) { - cmHandleValuesHolder.getOldValues() - .setCmHandleState(mapCmHandleStateToLcmEventCmHandleState(existingNcmpServiceCmHandle)); - cmHandleValuesHolder.getNewValues() - .setCmHandleState(mapCmHandleStateToLcmEventCmHandleState(targetNcmpServiceCmHandle)); - } - - private static void setPublicCmHandlePropertiesChange(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle, - final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder) { - - final Map> publicCmHandlePropertiesDifference = - getPublicCmHandlePropertiesDifference(targetNcmpServiceCmHandle.getPublicProperties(), - existingNcmpServiceCmHandle.getPublicProperties()); - cmHandleValuesHolder.getOldValues() - .setCmHandleProperties(List.of(publicCmHandlePropertiesDifference.get("oldValues"))); - cmHandleValuesHolder.getNewValues() - .setCmHandleProperties(List.of(publicCmHandlePropertiesDifference.get("newValues"))); - - } - - private static Values.CmHandleState mapCmHandleStateToLcmEventCmHandleState( - final NcmpServiceCmHandle ncmpServiceCmHandle) { - return Values.CmHandleState.fromValue(ncmpServiceCmHandle.getCompositeState().getCmHandleState().name()); - } - - private static Boolean getDataSyncEnabledFlag(final NcmpServiceCmHandle ncmpServiceCmHandle) { - return ncmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); - } - - private static boolean hasDataSyncEnabledFlagChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - - final Boolean targetDataSyncFlag = targetNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); - final Boolean existingDataSyncFlag = existingNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); - - if (targetDataSyncFlag == null) { - return existingDataSyncFlag != null; - } - - return !targetDataSyncFlag.equals(existingDataSyncFlag); - } - - private static boolean hasCmHandleStateChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - - return targetNcmpServiceCmHandle.getCompositeState().getCmHandleState() - != existingNcmpServiceCmHandle.getCompositeState().getCmHandleState(); - } - - private static boolean arePublicCmHandlePropertiesEqual(final Map targetCmHandleProperties, - final Map existingCmHandleProperties) { - if (targetCmHandleProperties.size() != existingCmHandleProperties.size()) { - return false; - } - - return targetCmHandleProperties.equals(existingCmHandleProperties); - } - - private static Map> getPublicCmHandlePropertiesDifference( - final Map targetCmHandleProperties, final Map existingCmHandleProperties) { - final Map> oldAndNewPropertiesDifferenceMap = new HashMap<>(2); - - final MapDifference cmHandlePropertiesDifference = - Maps.difference(targetCmHandleProperties, existingCmHandleProperties); - - final Map newValues = new HashMap<>(cmHandlePropertiesDifference.entriesOnlyOnLeft()); - final Map oldValues = new HashMap<>(cmHandlePropertiesDifference.entriesOnlyOnRight()); - - cmHandlePropertiesDifference.entriesDiffering().keySet().forEach(cmHandlePropertyName -> { - oldValues.put(cmHandlePropertyName, existingCmHandleProperties.get(cmHandlePropertyName)); - newValues.put(cmHandlePropertyName, targetCmHandleProperties.get(cmHandlePropertyName)); - }); - - oldAndNewPropertiesDifferenceMap.put("oldValues", oldValues); - oldAndNewPropertiesDifferenceMap.put("newValues", newValues); - - return oldAndNewPropertiesDifferenceMap; - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsService.java deleted file mode 100644 index 2eba83053..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsService.java +++ /dev/null @@ -1,68 +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.event.lcm; - -import io.micrometer.core.annotation.Timed; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.event.EventsPublisher; -import org.onap.ncmp.cmhandle.event.lcm.LcmEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.kafka.KafkaException; -import org.springframework.stereotype.Service; - -/** - * LcmEventsService to call the publisher and publish on the dedicated topic. - */ - -@Slf4j -@Service -@RequiredArgsConstructor -public class LcmEventsService { - - private final EventsPublisher eventsPublisher; - - @Value("${app.lcm.events.topic:ncmp-events}") - private String topicName; - - @Value("${notification.enabled:true}") - private boolean notificationsEnabled; - - /** - * Publish the LcmEvent to the public topic. - * - * @param cmHandleId Cm Handle Id - * @param lcmEvent Lcm Event - */ - @Timed(value = "cps.ncmp.lcm.events.publish", - description = "Time taken to publish a LCM event") - public void publishLcmEvent(final String cmHandleId, final LcmEvent lcmEvent) { - if (notificationsEnabled) { - try { - eventsPublisher.publishEvent(topicName, cmHandleId, lcmEvent); - } catch (final KafkaException e) { - log.error("Unable to publish message to topic : {} and cause : {}", topicName, e.getMessage()); - } - } else { - log.debug("Notifications disabled."); - } - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/EventsPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/EventsPublisher.java new file mode 100644 index 000000000..ec344bbae --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/EventsPublisher.java @@ -0,0 +1,66 @@ +/* + * ============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; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.SendResult; +import org.springframework.stereotype.Service; +import org.springframework.util.concurrent.ListenableFuture; +import org.springframework.util.concurrent.ListenableFutureCallback; + +/** + * EventsPublisher to publish events. + */ + +@Slf4j +@Service +@RequiredArgsConstructor +public class EventsPublisher { + + private final KafkaTemplate eventKafkaTemplate; + + /** + * LCM Event publisher. + * + * @param topicName valid topic name + * @param eventKey message key + * @param event message payload + */ + public void publishEvent(final String topicName, final String eventKey, final T event) { + final ListenableFuture> eventFuture = + eventKafkaTemplate.send(topicName, eventKey, event); + + eventFuture.addCallback(new ListenableFutureCallback<>() { + @Override + public void onFailure(final Throwable throwable) { + log.error("Unable to publish event to topic : {} due to {}", topicName, throwable.getMessage()); + } + + @Override + public void onSuccess(final SendResult sendResult) { + log.debug("Successfully published event to topic : {} , Event : {}", + sendResult.getRecordMetadata().topic(), sendResult.getProducerRecord().value()); + } + }); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java new file mode 100644 index 000000000..3b5b5aaa0 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java @@ -0,0 +1,53 @@ +/* + * ============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.avc; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.event.model.AvcEvent; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +/** + * Listener for AVC events. + */ +@Component +@Slf4j +@RequiredArgsConstructor +@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) +public class AvcEventConsumer { + + private final AvcEventProducer avcEventProducer; + + /** + * Consume the specified event. + * + * @param avcEvent the event to be consumed and produced. + */ + @KafkaListener( + topics = "${app.dmi.cm-events.topic}", + properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.AvcEvent"}) + public void consumeAndForward(final AvcEvent avcEvent) { + log.debug("Consuming AVC event {} ...", avcEvent); + avcEventProducer.sendMessage(avcEvent); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventMapper.java new file mode 100644 index 000000000..113da0deb --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventMapper.java @@ -0,0 +1,44 @@ +/* + * ============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.avc; + +import java.util.UUID; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.event.model.AvcEvent; + + +/** + * Mapper for converting incoming {@link AvcEvent} to outgoing {@link AvcEvent}. + */ +@Mapper(componentModel = "spring") +public interface AvcEventMapper { + + @Mapping(source = "eventId", target = "eventId", qualifiedByName = "avcEventId") + AvcEvent toOutgoingAvcEvent(AvcEvent incomingAvcEvent); + + @Named("avcEventId") + static String getAvcEventId(String eventId) { + return UUID.randomUUID().toString(); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducer.java new file mode 100644 index 000000000..15cbeb889 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducer.java @@ -0,0 +1,56 @@ +/* + * ============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.avc; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.event.model.AvcEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +/** + * Producer for AVC events. + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AvcEventProducer { + + private final KafkaTemplate kafkaTemplate; + + private final AvcEventMapper avcEventMapper; + + @Value("${app.ncmp.avc.cm-events-topic}") + private String cmEventsTopic; + + /** + * Sends message to the configured topic with a message key. + * + * @param incomingAvcEvent message payload + */ + public void sendMessage(final AvcEvent incomingAvcEvent) { + // generate new event id while keeping other data + final AvcEvent outgoingAvcEvent = avcEventMapper.toOutgoingAvcEvent(incomingAvcEvent); + log.debug("Forwarding AVC event {} to topic {} ", outgoingAvcEvent.getEventId(), cmEventsTopic); + kafkaTemplate.send(cmEventsTopic, outgoingAvcEvent.getEventId(), outgoingAvcEvent); + } +} 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 new file mode 100644 index 000000000..7717db67a --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumer.java @@ -0,0 +1,88 @@ +/* + * ============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 lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.event.model.InnerSubscriptionEvent; +import org.onap.cps.ncmp.event.model.SubscriptionEvent; +import org.onap.cps.spi.exceptions.OperationNotYetSupportedException; +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; + + @Value("${notification.enabled:true}") + private boolean notificationFeatureEnabled; + + @Value("${ncmp.model-loader.subscription:false}") + private boolean subscriptionModelLoaderEnabled; + + /** + * Consume the specified event. + * + * @param subscriptionEvent the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.subscription-topic}", + properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.SubscriptionEvent"}) + public void consumeSubscriptionEvent(final SubscriptionEvent subscriptionEvent) { + final InnerSubscriptionEvent event = subscriptionEvent.getEvent(); + final String eventDatastore = event.getPredicates().getDatastore(); + if (!(eventDatastore.equals("passthrough-running") || eventDatastore.equals("passthrough-operational"))) { + throw new OperationNotYetSupportedException( + "passthrough datastores are currently only supported for event subscriptions"); + } + if ("CM".equals(event.getDataType().getDataCategory())) { + log.debug("Consuming event {} ...", subscriptionEvent); + if (subscriptionModelLoaderEnabled) { + persistSubscriptionEvent(subscriptionEvent); + } + if ("CREATE".equals(subscriptionEvent.getEventType().value())) { + log.info("Subscription for ClientID {} with name {} ...", + event.getSubscription().getClientID(), + event.getSubscription().getName()); + if (notificationFeatureEnabled) { + subscriptionEventForwarder.forwardCreateSubscriptionEvent(subscriptionEvent); + } + } + } 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 new file mode 100644 index 000000000..c3624b800 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java @@ -0,0 +1,106 @@ +/* + * ============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.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.events.EventsPublisher; +import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.inventory.InventoryPersistence; +import org.onap.cps.ncmp.event.model.SubscriptionEvent; +import org.onap.cps.spi.exceptions.OperationNotYetSupportedException; +import org.springframework.stereotype.Component; + + +@Component +@Slf4j +@RequiredArgsConstructor +public class SubscriptionEventForwarder { + + private final InventoryPersistence inventoryPersistence; + private final EventsPublisher eventsPublisher; + + private static final String DMI_AVC_SUBSCRIPTION_TOPIC_PREFIX = "ncmp-dmi-cm-avc-subscription-"; + + /** + * Forward subscription event. + * + * @param subscriptionEvent the event to be forwarded + */ + public void forwardCreateSubscriptionEvent(final SubscriptionEvent subscriptionEvent) { + final List cmHandleTargets = subscriptionEvent.getEvent().getPredicates().getTargets(); + if (cmHandleTargets == null || cmHandleTargets.isEmpty() + || cmHandleTargets.stream().anyMatch(id -> ((String) id).contains("*"))) { + throw new OperationNotYetSupportedException( + "CMHandle targets are required. \"Wildcard\" operations are not yet supported"); + } + final List cmHandleTargetsAsStrings = cmHandleTargets.stream().map( + Objects::toString).collect(Collectors.toList()); + final Collection yangModelCmHandles = + inventoryPersistence.getYangModelCmHandles(cmHandleTargetsAsStrings); + final Map>> dmiNameCmHandleMap = + organizeByDmiName(yangModelCmHandles); + dmiNameCmHandleMap.forEach((dmiName, cmHandlePropertiesMap) -> { + subscriptionEvent.getEvent().getPredicates().setTargets(Collections.singletonList(cmHandlePropertiesMap)); + final String eventKey = createEventKey(subscriptionEvent, dmiName); + eventsPublisher.publishEvent(DMI_AVC_SUBSCRIPTION_TOPIC_PREFIX + dmiName, eventKey, subscriptionEvent); + }); + } + + private Map>> organizeByDmiName( + final Collection yangModelCmHandles) { + final Map>> dmiNameCmHandlePropertiesMap = new HashMap<>(); + yangModelCmHandles.forEach(cmHandle -> { + final String dmiName = cmHandle.resolveDmiServiceName(RequiredDmiService.DATA); + if (!dmiNameCmHandlePropertiesMap.containsKey(dmiName)) { + final Map> cmHandleDmiPropertiesMap = new HashMap<>(); + cmHandleDmiPropertiesMap.put(cmHandle.getId(), dmiPropertiesAsMap(cmHandle)); + dmiNameCmHandlePropertiesMap.put(cmHandle.getDmiDataServiceName(), cmHandleDmiPropertiesMap); + } else { + dmiNameCmHandlePropertiesMap.get(cmHandle.getDmiDataServiceName()) + .put(cmHandle.getId(), dmiPropertiesAsMap(cmHandle)); + } + }); + return dmiNameCmHandlePropertiesMap; + } + + private String createEventKey(final SubscriptionEvent subscriptionEvent, final String dmiName) { + return subscriptionEvent.getEvent().getSubscription().getClientID() + + "-" + + subscriptionEvent.getEvent().getSubscription().getName() + + "-" + + dmiName; + } + + public Map dmiPropertiesAsMap(final YangModelCmHandle yangModelCmHandle) { + return yangModelCmHandle.getDmiProperties().stream().collect( + Collectors.toMap(YangModelCmHandle.Property::getName, YangModelCmHandle.Property::getValue)); + } + +} 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 new file mode 100644 index 000000000..3c238dda2 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventMapper.java @@ -0,0 +1,47 @@ +/* + * ============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.event.model.SubscriptionEvent; + +@Mapper(componentModel = "spring") +public interface SubscriptionEventMapper { + + @Mapping(source = "event.subscription.clientID", target = "clientId") + @Mapping(source = "event.subscription.name", target = "subscriptionName") + @Mapping(source = "event.subscription.isTagged", target = "tagged") + @Mapping(source = "event.predicates.targets", + target = "predicates.targetCmHandles", qualifiedByName = "mapTargetsToCmHandleTargets") + @Mapping(source = "event.predicates.datastore", target = "predicates.datastore") + YangModelSubscriptionEvent toYangModelSubscriptionEvent(SubscriptionEvent subscriptionEvent); + + @Named("mapTargetsToCmHandleTargets") + default List mapTargetsToCmHandleTargets(List targets) { + return targets.stream().map( + target -> new YangModelSubscriptionEvent.TargetCmHandle(target.toString())).collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java new file mode 100644 index 000000000..a8d00f7e3 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java @@ -0,0 +1,38 @@ +/* + * ============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.lcm; + +public enum LcmEventType { + + CREATE("create"), UPDATE("update"), DELETE("delete"); + + private final String eventName; + + private final String eventTypeTemplate = "org.onap.ncmp.cmhandle-lcm-event.%s"; + + LcmEventType(final String eventName) { + this.eventName = String.format(eventTypeTemplate, eventName); + } + + public String getEventType() { + return this.eventName; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java new file mode 100644 index 000000000..18bdcbeaa --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java @@ -0,0 +1,58 @@ +/* + * ============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.lcm; + +import java.util.Map; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.inventory.CmHandleState; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; + +/** + * The implementation of it should handle the persisting of composite state and delegate the request to publish the + * corresponding lcm event. + */ +public interface LcmEventsCmHandleStateHandler { + + /** + * Updates the composite state of cmHandle based on cmHandleState. + * + * @param yangModelCmHandle cm handle represented as yang model + * @param targetCmHandleState target cm handle state + */ + void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState); + + /** + * Updates the composite state of cmHandle based on cmHandleState in batch. + * + * @param cmHandleStatePerCmHandle Map of Yang Model Cm Handle and corresponding cm handle state. + */ + void updateCmHandleStateBatch(final Map cmHandleStatePerCmHandle); + + /** + * Publish LCM Event. + * + * @param targetNcmpServiceCmHandle target NcmpServiceCmHandle + * @param currentNcmpServiceCmHandle current NcmpServiceCmHandle + */ + void publishLcmEventAsynchronously(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle currentNcmpServiceCmHandle); + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java new file mode 100644 index 000000000..9d518432a --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java @@ -0,0 +1,227 @@ +/* + * ============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.lcm; + +import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED; +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED; +import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED; +import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY; + +import io.micrometer.core.annotation.Timed; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.inventory.CmHandleState; +import org.onap.cps.ncmp.api.inventory.CompositeState; +import org.onap.cps.ncmp.api.inventory.CompositeStateUtils; +import org.onap.cps.ncmp.api.inventory.InventoryPersistence; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.ncmp.cmhandle.event.lcm.LcmEvent; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleStateHandler { + + private final InventoryPersistence inventoryPersistence; + private final LcmEventsCreator lcmEventsCreator; + private final LcmEventsService lcmEventsService; + + @Override + public void updateCmHandleState(final YangModelCmHandle updatedYangModelCmHandle, + final CmHandleState targetCmHandleState) { + + final CompositeState compositeState = updatedYangModelCmHandle.getCompositeState(); + + if (isCompositeStateSame(compositeState, targetCmHandleState)) { + log.debug("CmHandle with id : {} already in state : {}", updatedYangModelCmHandle.getId(), + targetCmHandleState); + } else { + final YangModelCmHandle currentYangModelCmHandle = YangModelCmHandle.deepCopyOf(updatedYangModelCmHandle); + updateToSpecifiedCmHandleState(updatedYangModelCmHandle, targetCmHandleState); + persistCmHandle(updatedYangModelCmHandle, currentYangModelCmHandle); + publishLcmEventAsynchronously(toNcmpServiceCmHandle(updatedYangModelCmHandle), + toNcmpServiceCmHandle(currentYangModelCmHandle)); + } + } + + @Override + @Timed(value = "cps.ncmp.cmhandle.state.update.batch", + description = "Time taken to update a batch of cm handle states") + public void updateCmHandleStateBatch(final Map cmHandleStatePerCmHandle) { + final Collection cmHandleTransitionPairs = + prepareCmHandleTransitionBatch(cmHandleStatePerCmHandle); + persistCmHandleBatch(cmHandleTransitionPairs); + publishLcmEventBatchAsynchronously(cmHandleTransitionPairs); + } + + @Async("notificationExecutor") + @Override + public void publishLcmEventAsynchronously(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle currentNcmpServiceCmHandle) { + publishLcmEvent(targetNcmpServiceCmHandle, currentNcmpServiceCmHandle); + } + + /** + * Publish LcmEvent in batches and in asynchronous manner. + * + * @param cmHandleTransitionPairs Pair of existing and modified cm handle represented as YangModelCmHandle + */ + @Async("notificationExecutor") + public void publishLcmEventBatchAsynchronously(final Collection cmHandleTransitionPairs) { + cmHandleTransitionPairs.forEach(cmHandleTransitionPair -> publishLcmEvent( + toNcmpServiceCmHandle(cmHandleTransitionPair.getTargetYangModelCmHandle()), + toNcmpServiceCmHandle(cmHandleTransitionPair.getCurrentYangModelCmHandle()))); + } + + private void publishLcmEvent(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + final String cmHandleId = targetNcmpServiceCmHandle.getCmHandleId(); + final LcmEvent lcmEvent = + lcmEventsCreator.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + lcmEventsService.publishLcmEvent(cmHandleId, lcmEvent); + } + + private Collection prepareCmHandleTransitionBatch( + final Map cmHandleStatePerCmHandle) { + final List cmHandleTransitionPairs = new ArrayList<>(cmHandleStatePerCmHandle.size()); + cmHandleStatePerCmHandle.forEach((yangModelCmHandle, targetCmHandleState) -> { + + final CompositeState compositeState = yangModelCmHandle.getCompositeState(); + + if (isCompositeStateSame(compositeState, targetCmHandleState)) { + log.debug("CmHandle with id : {} already in state : {}", yangModelCmHandle.getId(), + targetCmHandleState); + } else { + final CmHandleTransitionPair cmHandleTransitionPair = new CmHandleTransitionPair(); + cmHandleTransitionPair.setCurrentYangModelCmHandle(YangModelCmHandle.deepCopyOf(yangModelCmHandle)); + updateToSpecifiedCmHandleState(yangModelCmHandle, targetCmHandleState); + cmHandleTransitionPair.setTargetYangModelCmHandle(yangModelCmHandle); + cmHandleTransitionPairs.add(cmHandleTransitionPair); + } + }); + + return cmHandleTransitionPairs; + } + + + private void persistCmHandle(final YangModelCmHandle targetYangModelCmHandle, + final YangModelCmHandle currentYangModelCmHandle) { + if (isNew(currentYangModelCmHandle.getCompositeState(), targetYangModelCmHandle.getCompositeState())) { + log.debug("Registering a new cm handle {}", targetYangModelCmHandle.getId()); + inventoryPersistence.saveCmHandle(targetYangModelCmHandle); + } else if (isDeleted(targetYangModelCmHandle.getCompositeState())) { + log.info("CmHandle with Id : {} is DELETED", targetYangModelCmHandle.getId()); + } else { + inventoryPersistence.saveCmHandleState(targetYangModelCmHandle.getId(), + targetYangModelCmHandle.getCompositeState()); + } + } + + private void persistCmHandleBatch(final Collection cmHandleTransitionPairs) { + + final List newCmHandles = new ArrayList<>(); + final Map compositeStatePerCmHandleId = new LinkedHashMap<>(); + + cmHandleTransitionPairs.forEach(cmHandleTransitionPair -> { + if (isNew(cmHandleTransitionPair.getCurrentYangModelCmHandle().getCompositeState(), + cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState())) { + newCmHandles.add(cmHandleTransitionPair.getTargetYangModelCmHandle()); + } else if (!isDeleted(cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState())) { + compositeStatePerCmHandleId.put(cmHandleTransitionPair.getTargetYangModelCmHandle().getId(), + cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState()); + } + }); + + inventoryPersistence.saveCmHandleBatch(newCmHandles); + inventoryPersistence.saveCmHandleStateBatch(compositeStatePerCmHandleId); + + } + + private void updateToSpecifiedCmHandleState(final YangModelCmHandle yangModelCmHandle, + final CmHandleState targetCmHandleState) { + + if (READY == targetCmHandleState) { + setInitialStates(yangModelCmHandle); + } else if (ADVISED == targetCmHandleState) { + if (yangModelCmHandle.getCompositeState() == null) { + registerNewCmHandle(yangModelCmHandle); + } else if (yangModelCmHandle.getCompositeState().getCmHandleState() == LOCKED) { + retryCmHandle(yangModelCmHandle); + } + } else { + setCmHandleState(yangModelCmHandle, targetCmHandleState); + } + } + + private void setInitialStates(final YangModelCmHandle yangModelCmHandle) { + CompositeStateUtils.setInitialDataStoreSyncState().accept(yangModelCmHandle.getCompositeState()); + CompositeStateUtils.setCompositeState(READY).accept(yangModelCmHandle.getCompositeState()); + } + + private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) { + CompositeStateUtils.setCompositeStateForRetry().accept(yangModelCmHandle.getCompositeState()); + } + + private void registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) { + yangModelCmHandle.setCompositeState(new CompositeState()); + setCmHandleState(yangModelCmHandle, ADVISED); + } + + private void setCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState) { + CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState()); + } + + private boolean isNew(final CompositeState existingCompositeState, final CompositeState targetCompositeState) { + return (existingCompositeState == null && targetCompositeState.getCmHandleState() == ADVISED); + } + + private boolean isDeleted(final CompositeState targetCompositeState) { + return targetCompositeState.getCmHandleState() == DELETED; + } + + private boolean isCompositeStateSame(final CompositeState compositeState, final CmHandleState targetCmHandleState) { + return (compositeState != null && compositeState.getCmHandleState() == targetCmHandleState); + } + + private NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) { + return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle); + } + + @Getter + @Setter + @NoArgsConstructor + static class CmHandleTransitionPair { + private YangModelCmHandle currentYangModelCmHandle; + private YangModelCmHandle targetYangModelCmHandle; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java new file mode 100644 index 000000000..a72e664dc --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java @@ -0,0 +1,100 @@ +/* + * ============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.lcm; + +import java.util.UUID; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.ncmp.cmhandle.event.lcm.Event; +import org.onap.ncmp.cmhandle.event.lcm.LcmEvent; +import org.onap.ncmp.cmhandle.event.lcm.Values; +import org.springframework.stereotype.Component; + + +/** + * LcmEventsCreator to create LcmEvent based on relevant operation. + */ +@Slf4j +@Component +public class LcmEventsCreator { + + /** + * Populate Lifecycle Management Event. + * + * @param cmHandleId cm handle identifier + * @param targetNcmpServiceCmHandle target ncmp service cmhandle + * @param existingNcmpServiceCmHandle existing ncmp service cmhandle + * @return Populated LcmEvent + */ + public LcmEvent populateLcmEvent(final String cmHandleId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + return createLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + } + + private LcmEvent createLcmEvent(final String cmHandleId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + final LcmEventType lcmEventType = + LcmEventsCreatorHelper.determineEventType(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + final LcmEvent lcmEvent = lcmEventHeader(cmHandleId, lcmEventType); + lcmEvent.setEvent( + lcmEventPayload(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, lcmEventType)); + return lcmEvent; + } + + private Event lcmEventPayload(final String eventCorrelationId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle, final LcmEventType lcmEventType) { + final Event event = new Event(); + event.setCmHandleId(eventCorrelationId); + final CmHandleValuesHolder cmHandleValuesHolder = + LcmEventsCreatorHelper.determineEventValues(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, + lcmEventType); + event.setOldValues(cmHandleValuesHolder.getOldValues()); + event.setNewValues(cmHandleValuesHolder.getNewValues()); + + return event; + } + + private LcmEvent lcmEventHeader(final String eventCorrelationId, final LcmEventType lcmEventType) { + final LcmEvent lcmEvent = new LcmEvent(); + lcmEvent.setEventId(UUID.randomUUID().toString()); + lcmEvent.setEventCorrelationId(eventCorrelationId); + lcmEvent.setEventTime(EventDateTimeFormatter.getCurrentDateTime()); + lcmEvent.setEventSource("org.onap.ncmp"); + lcmEvent.setEventType(lcmEventType.getEventType()); + lcmEvent.setEventSchema("org.onap.ncmp:cmhandle-lcm-event"); + lcmEvent.setEventSchemaVersion("1.0"); + return lcmEvent; + } + + @NoArgsConstructor + @Getter + @Setter + static class CmHandleValuesHolder { + + private Values oldValues; + private Values newValues; + } + +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java new file mode 100644 index 000000000..1322b7277 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java @@ -0,0 +1,227 @@ +/* + * ============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.lcm; + +import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.CREATE; +import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.DELETE; +import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.UPDATE; +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED; + +import com.google.common.collect.MapDifference; +import com.google.common.collect.Maps; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.ncmp.cmhandle.event.lcm.Values; + +/** + * LcmEventsCreatorHelper has helper methods to create LcmEvent. + * Determine the lcm event type i.e create,update and delete. + * Based on lcm event type create the LcmEvent payload. + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LcmEventsCreatorHelper { + + /** + * Determining the event type based on the composite state. + * + * @param targetNcmpServiceCmHandle target ncmpServiceCmHandle + * @param existingNcmpServiceCmHandle existing ncmpServiceCmHandle + * @return Event Type + */ + public static LcmEventType determineEventType(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + + if (existingNcmpServiceCmHandle.getCompositeState() == null) { + return CREATE; + } else if (targetNcmpServiceCmHandle.getCompositeState().getCmHandleState() == DELETED) { + return DELETE; + } + return UPDATE; + } + + /** + * Determine the cmhandle value difference pair.Contains the difference in the form of oldValues and newValues. + * + * @param targetNcmpServiceCmHandle target ncmpServiceCmHandle + * @param existingNcmpServiceCmHandle existing ncmpServiceCmHandle + * @param lcmEventType lcm event type + * @return Lcm Event Value difference pair + */ + public static LcmEventsCreator.CmHandleValuesHolder determineEventValues( + final NcmpServiceCmHandle targetNcmpServiceCmHandle, final NcmpServiceCmHandle existingNcmpServiceCmHandle, + final LcmEventType lcmEventType) { + + if (CREATE == lcmEventType) { + return determineCreateEventValues(targetNcmpServiceCmHandle); + } else if (UPDATE == lcmEventType) { + return determineUpdateEventValues(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + } + return new LcmEventsCreator.CmHandleValuesHolder(); + + } + + private static LcmEventsCreator.CmHandleValuesHolder determineCreateEventValues( + final NcmpServiceCmHandle ncmpServiceCmHandle) { + final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder = new LcmEventsCreator.CmHandleValuesHolder(); + cmHandleValuesHolder.setNewValues(new Values()); + cmHandleValuesHolder.getNewValues().setDataSyncEnabled(getDataSyncEnabledFlag(ncmpServiceCmHandle)); + cmHandleValuesHolder.getNewValues() + .setCmHandleState(mapCmHandleStateToLcmEventCmHandleState(ncmpServiceCmHandle)); + cmHandleValuesHolder.getNewValues().setCmHandleProperties(List.of(ncmpServiceCmHandle.getPublicProperties())); + return cmHandleValuesHolder; + } + + private static LcmEventsCreator.CmHandleValuesHolder determineUpdateEventValues( + final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + + final boolean hasDataSyncFlagEnabledChanged = + hasDataSyncEnabledFlagChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + final boolean hasCmHandleStateChanged = + hasCmHandleStateChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + final boolean arePublicCmHandlePropertiesEqual = + arePublicCmHandlePropertiesEqual(targetNcmpServiceCmHandle.getPublicProperties(), + existingNcmpServiceCmHandle.getPublicProperties()); + + final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder = new LcmEventsCreator.CmHandleValuesHolder(); + + if (hasDataSyncFlagEnabledChanged || hasCmHandleStateChanged || (!arePublicCmHandlePropertiesEqual)) { + cmHandleValuesHolder.setOldValues(new Values()); + cmHandleValuesHolder.setNewValues(new Values()); + } else { + return cmHandleValuesHolder; + } + + if (hasDataSyncFlagEnabledChanged) { + setDataSyncEnabledFlag(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, cmHandleValuesHolder); + } + + if (hasCmHandleStateChanged) { + setCmHandleStateChange(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, cmHandleValuesHolder); + } + + if (!arePublicCmHandlePropertiesEqual) { + setPublicCmHandlePropertiesChange(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, + cmHandleValuesHolder); + } + + return cmHandleValuesHolder; + + } + + private static void setDataSyncEnabledFlag(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle, + final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder) { + + cmHandleValuesHolder.getOldValues().setDataSyncEnabled(getDataSyncEnabledFlag(existingNcmpServiceCmHandle)); + cmHandleValuesHolder.getNewValues().setDataSyncEnabled(getDataSyncEnabledFlag(targetNcmpServiceCmHandle)); + + } + + private static void setCmHandleStateChange(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle, + final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder) { + cmHandleValuesHolder.getOldValues() + .setCmHandleState(mapCmHandleStateToLcmEventCmHandleState(existingNcmpServiceCmHandle)); + cmHandleValuesHolder.getNewValues() + .setCmHandleState(mapCmHandleStateToLcmEventCmHandleState(targetNcmpServiceCmHandle)); + } + + private static void setPublicCmHandlePropertiesChange(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle, + final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder) { + + final Map> publicCmHandlePropertiesDifference = + getPublicCmHandlePropertiesDifference(targetNcmpServiceCmHandle.getPublicProperties(), + existingNcmpServiceCmHandle.getPublicProperties()); + cmHandleValuesHolder.getOldValues() + .setCmHandleProperties(List.of(publicCmHandlePropertiesDifference.get("oldValues"))); + cmHandleValuesHolder.getNewValues() + .setCmHandleProperties(List.of(publicCmHandlePropertiesDifference.get("newValues"))); + + } + + private static Values.CmHandleState mapCmHandleStateToLcmEventCmHandleState( + final NcmpServiceCmHandle ncmpServiceCmHandle) { + return Values.CmHandleState.fromValue(ncmpServiceCmHandle.getCompositeState().getCmHandleState().name()); + } + + private static Boolean getDataSyncEnabledFlag(final NcmpServiceCmHandle ncmpServiceCmHandle) { + return ncmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); + } + + private static boolean hasDataSyncEnabledFlagChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + + final Boolean targetDataSyncFlag = targetNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); + final Boolean existingDataSyncFlag = existingNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); + + if (targetDataSyncFlag == null) { + return existingDataSyncFlag != null; + } + + return !targetDataSyncFlag.equals(existingDataSyncFlag); + } + + private static boolean hasCmHandleStateChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + + return targetNcmpServiceCmHandle.getCompositeState().getCmHandleState() + != existingNcmpServiceCmHandle.getCompositeState().getCmHandleState(); + } + + private static boolean arePublicCmHandlePropertiesEqual(final Map targetCmHandleProperties, + final Map existingCmHandleProperties) { + if (targetCmHandleProperties.size() != existingCmHandleProperties.size()) { + return false; + } + + return targetCmHandleProperties.equals(existingCmHandleProperties); + } + + private static Map> getPublicCmHandlePropertiesDifference( + final Map targetCmHandleProperties, final Map existingCmHandleProperties) { + final Map> oldAndNewPropertiesDifferenceMap = new HashMap<>(2); + + final MapDifference cmHandlePropertiesDifference = + Maps.difference(targetCmHandleProperties, existingCmHandleProperties); + + final Map newValues = new HashMap<>(cmHandlePropertiesDifference.entriesOnlyOnLeft()); + final Map oldValues = new HashMap<>(cmHandlePropertiesDifference.entriesOnlyOnRight()); + + cmHandlePropertiesDifference.entriesDiffering().keySet().forEach(cmHandlePropertyName -> { + oldValues.put(cmHandlePropertyName, existingCmHandleProperties.get(cmHandlePropertyName)); + newValues.put(cmHandlePropertyName, targetCmHandleProperties.get(cmHandlePropertyName)); + }); + + oldAndNewPropertiesDifferenceMap.put("oldValues", oldValues); + oldAndNewPropertiesDifferenceMap.put("newValues", newValues); + + return oldAndNewPropertiesDifferenceMap; + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java new file mode 100644 index 000000000..f258b4597 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java @@ -0,0 +1,68 @@ +/* + * ============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.lcm; + +import io.micrometer.core.annotation.Timed; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.events.EventsPublisher; +import org.onap.ncmp.cmhandle.event.lcm.LcmEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.KafkaException; +import org.springframework.stereotype.Service; + +/** + * LcmEventsService to call the publisher and publish on the dedicated topic. + */ + +@Slf4j +@Service +@RequiredArgsConstructor +public class LcmEventsService { + + private final EventsPublisher eventsPublisher; + + @Value("${app.lcm.events.topic:ncmp-events}") + private String topicName; + + @Value("${notification.enabled:true}") + private boolean notificationsEnabled; + + /** + * Publish the LcmEvent to the public topic. + * + * @param cmHandleId Cm Handle Id + * @param lcmEvent Lcm Event + */ + @Timed(value = "cps.ncmp.lcm.events.publish", + description = "Time taken to publish a LCM event") + public void publishLcmEvent(final String cmHandleId, final LcmEvent lcmEvent) { + if (notificationsEnabled) { + try { + eventsPublisher.publishEvent(topicName, cmHandleId, lcmEvent); + } catch (final KafkaException e) { + log.error("Unable to publish message to topic : {} and cause : {}", topicName, e.getMessage()); + } + } else { + log.debug("Notifications disabled."); + } + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java deleted file mode 100644 index 58290a7e9..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java +++ /dev/null @@ -1,53 +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.notifications.avc; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.event.model.AvcEvent; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - -/** - * Listener for AVC events. - */ -@Component -@Slf4j -@RequiredArgsConstructor -@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) -public class AvcEventConsumer { - - private final AvcEventProducer avcEventProducer; - - /** - * Consume the specified event. - * - * @param avcEvent the event to be consumed and produced. - */ - @KafkaListener( - topics = "${app.dmi.cm-events.topic}", - properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.AvcEvent"}) - public void consumeAndForward(final AvcEvent avcEvent) { - log.debug("Consuming AVC event {} ...", avcEvent); - avcEventProducer.sendMessage(avcEvent); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java deleted file mode 100644 index adbf08fa2..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java +++ /dev/null @@ -1,44 +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.notifications.avc; - -import java.util.UUID; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.onap.cps.ncmp.event.model.AvcEvent; - - -/** - * Mapper for converting incoming {@link AvcEvent} to outgoing {@link AvcEvent}. - */ -@Mapper(componentModel = "spring") -public interface AvcEventMapper { - - @Mapping(source = "eventId", target = "eventId", qualifiedByName = "avcEventId") - AvcEvent toOutgoingAvcEvent(AvcEvent incomingAvcEvent); - - @Named("avcEventId") - static String getAvcEventId(String eventId) { - return UUID.randomUUID().toString(); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java deleted file mode 100644 index b8fe730a1..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java +++ /dev/null @@ -1,56 +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.notifications.avc; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.event.model.AvcEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.stereotype.Service; - -/** - * Producer for AVC events. - */ -@Slf4j -@Service -@RequiredArgsConstructor -public class AvcEventProducer { - - private final KafkaTemplate kafkaTemplate; - - private final AvcEventMapper avcEventMapper; - - @Value("${app.ncmp.avc.cm-events-topic}") - private String cmEventsTopic; - - /** - * Sends message to the configured topic with a message key. - * - * @param incomingAvcEvent message payload - */ - public void sendMessage(final AvcEvent incomingAvcEvent) { - // generate new event id while keeping other data - final AvcEvent outgoingAvcEvent = avcEventMapper.toOutgoingAvcEvent(incomingAvcEvent); - log.debug("Forwarding AVC event {} to topic {} ", outgoingAvcEvent.getEventId(), cmEventsTopic); - kafkaTemplate.send(cmEventsTopic, outgoingAvcEvent.getEventId(), outgoingAvcEvent); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java index d778afc3e..914b626e3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java @@ -29,7 +29,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler; +import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; import org.onap.cps.ncmp.api.inventory.CmHandleState; diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index f12969def..bd63813e7 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -26,7 +26,7 @@ import com.hazelcast.map.IMap import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService -import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler +import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.impl.exception.DmiRequestException import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index 4acd249e6..871af842e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -25,7 +25,7 @@ package org.onap.cps.ncmp.api.impl import com.hazelcast.map.IMap import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService -import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler +import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.inventory.CmHandleQueries import org.onap.cps.ncmp.api.inventory.CmHandleState diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumerSpec.groovy deleted file mode 100644 index d801e4ddf..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventConsumerSpec.groovy +++ /dev/null @@ -1,113 +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.event.avc - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.event.model.SubscriptionEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.spi.exceptions.OperationNotYetSupportedException -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 objectUnderTest = new SubscriptionEventConsumer(mockSubscriptionEventForwarder, mockSubscriptionEventMapper, mockSubscriptionPersistence) - - def yangModelSubscriptionEvent = new YangModelSubscriptionEvent() - - @Autowired - JsonObjectMapper jsonObjectMapper - - 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) - and: 'notifications are enabled' - objectUnderTest.notificationFeatureEnabled = true - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = true - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(testEventSent) - then: 'the event is mapped to a yangModelSubscription' - 1 * mockSubscriptionEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent - and: 'the event is persisted' - 1 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) - and: 'the event is forwarded' - 1 * mockSubscriptionEventForwarder.forwardCreateSubscriptionEvent(testEventSent) - } - - def 'Consume valid CM create message where notifications and model loader are disabled'() { - given: 'an event with data category CM' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - and: 'notifications are disabled' - objectUnderTest.notificationFeatureEnabled = false - and: 'subscription model loader is disabled' - objectUnderTest.subscriptionModelLoaderEnabled = false - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(testEventSent) - then: 'the event is not mapped to a yangModelSubscription' - 0 * mockSubscriptionEventMapper.toYangModelSubscriptionEvent(*_) >> yangModelSubscriptionEvent - and: 'the event is not persisted' - 0 * mockSubscriptionPersistence.saveSubscriptionEvent(*_) - and: 'the event is not forwarded' - 0 * mockSubscriptionEventForwarder.forwardCreateSubscriptionEvent(*_) - } - - def 'Consume valid FM message'() { - given: 'an event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - and: 'dataCategory is set to FM' - testEventSent.getEvent().getDataType().setDataCategory("FM") - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(testEventSent) - then: 'no exception is thrown' - noExceptionThrown() - and: 'the event is not mapped to a yangModelSubscription' - 0 * mockSubscriptionEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent - and: 'the event is not persisted' - 0 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) - and: 'No event is forwarded' - 0 * mockSubscriptionEventForwarder.forwardCreateSubscriptionEvent(*_) - } - - 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 non passthrough datastore' - testEventSent.getEvent().getPredicates().setDatastore("operational") - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(testEventSent) - then: 'an operation not yet supported exception is thrown' - thrown(OperationNotYetSupportedException) - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventForwarderSpec.groovy deleted file mode 100644 index f9e801ddb..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventForwarderSpec.groovy +++ /dev/null @@ -1,96 +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.event.avc - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.api.impl.event.EventsPublisher -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle -import org.onap.cps.ncmp.api.inventory.InventoryPersistence -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.event.model.SubscriptionEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.spi.exceptions.OperationNotYetSupportedException -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.kafka.core.KafkaTemplate -import org.springframework.util.concurrent.ListenableFuture; - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class SubscriptionEventForwarderSpec extends MessagingBaseSpec { - - def mockInventoryPersistence = Mock(InventoryPersistence) - def mockSubscriptionEventPublisher = Mock(EventsPublisher) - def objectUnderTest = new SubscriptionEventForwarder(mockInventoryPersistence, mockSubscriptionEventPublisher) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Forward valid CM create subscription'() { - 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"), - createYangModelCmHandleWithDmiProperty(3, 2,"shape","triangle") - ] - when: 'the valid event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(testEventSent) - then: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' - 1 * mockSubscriptionEventPublisher.publishEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", - subscriptionEvent -> { - Map targets = subscriptionEvent.getEvent().getPredicates().getTargets().get(0) - targets["CMHandle1"] == ["shape":"circle"] - targets["CMHandle2"] == ["shape":"square"] - } - ) - 1 * mockSubscriptionEventPublisher.publishEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", - subscriptionEvent -> { - Map targets = subscriptionEvent.getEvent().getPredicates().getTargets().get(0) - targets["CMHandle3"] == ["shape":"triangle"] - } - ) - } - - 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.getEvent().getPredicates().setTargets(invalidTargets) - when: 'the event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(testEventSent) - then: 'an operation not yet supported exception is thrown' - thrown(OperationNotYetSupportedException) - where: - scenario | invalidTargets - 'null' | null - 'empty' | [] - 'wildcard' | ['CMHandle*'] - } - - static def createYangModelCmHandleWithDmiProperty(id, dmiId,propertyName, propertyValue) { - return new YangModelCmHandle(id:"CMHandle" + id, dmiDataServiceName: "DMIName" + dmiId, dmiProperties: [new YangModelCmHandle.Property(propertyName,propertyValue)]) - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy deleted file mode 100644 index ddede6639..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy +++ /dev/null @@ -1,211 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 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.event.lcm - -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle -import org.onap.cps.ncmp.api.inventory.CompositeState -import org.onap.cps.ncmp.api.inventory.DataStoreSyncState -import org.onap.cps.ncmp.api.inventory.InventoryPersistence -import spock.lang.Specification - -import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED -import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED -import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETING -import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED -import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY -import static org.onap.cps.ncmp.api.inventory.LockReasonCategory.LOCKED_MODULE_SYNC_FAILED - -class LcmEventsCmHandleStateHandlerImplSpec extends Specification { - - def mockInventoryPersistence = Mock(InventoryPersistence) - def mockLcmEventsCreator = Mock(LcmEventsCreator) - def mockLcmEventsService = Mock(LcmEventsService) - - def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, mockLcmEventsCreator, mockLcmEventsService) - - def cmHandleId = 'cmhandle-id-1' - def compositeState - def yangModelCmHandle - - def 'Update and Publish Events on State Change #stateChange'() { - given: 'Cm Handle represented as YangModelCmHandle' - compositeState = new CompositeState(cmHandleState: fromCmHandleState) - yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) - when: 'update state is invoked' - objectUnderTest.updateCmHandleState(yangModelCmHandle, toCmHandleState) - then: 'state is saved using inventory persistence' - expectedCallsToInventoryPersistence * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) - and: 'event service is called to publish event' - expectedCallsToEventService * mockLcmEventsService.publishLcmEvent(cmHandleId, _) - where: 'state change parameters are provided' - stateChange | fromCmHandleState | toCmHandleState || expectedCallsToInventoryPersistence | expectedCallsToEventService - 'ADVISED to READY' | ADVISED | READY || 1 | 1 - 'READY to LOCKED' | READY | LOCKED || 1 | 1 - 'ADVISED to ADVISED' | ADVISED | ADVISED || 0 | 0 - 'READY to READY' | READY | READY || 0 | 0 - 'LOCKED to LOCKED' | LOCKED | LOCKED || 0 | 0 - - } - - def 'Update and Publish Events on State Change from NO_EXISTING state to ADVISED'() { - given: 'Cm Handle represented as YangModelCmHandle' - yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: []) - when: 'update state is invoked' - objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) - then: 'state is saved using inventory persistence' - 1 * mockInventoryPersistence.saveCmHandle(yangModelCmHandle) - and: 'event service is called to publish event' - 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) - } - - def 'Update and Publish Events on State Change from LOCKED to ADVISED'() { - given: 'Cm Handle represented as YangModelCmHandle in LOCKED state' - compositeState = new CompositeState(cmHandleState: LOCKED, - lockReason: CompositeState.LockReason.builder().lockReasonCategory(LOCKED_MODULE_SYNC_FAILED).details('some lock details').build()) - yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) - when: 'update state is invoked' - objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) - then: 'state is saved using inventory persistence and old lock reason details are retained' - 1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> { - args -> { - assert (args[1] as CompositeState).lockReason.details == 'some lock details' - } - } - and: 'event service is called to publish event' - 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) - } - - def 'Update and Publish Events on State Change to READY'() { - given: 'Cm Handle represented as YangModelCmHandle' - compositeState = new CompositeState(cmHandleState: ADVISED) - yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) - and: 'global sync flag is set' - compositeState.setDataSyncEnabled(false) - when: 'update cmhandle state is invoked' - objectUnderTest.updateCmHandleState(yangModelCmHandle, READY) - then: 'state is saved using inventory persistence with expected dataSyncState' - 1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> { - args-> { - def result = (args[1] as CompositeState) - assert result.dataSyncEnabled == false - assert result.dataStores.operationalDataStore.dataStoreSyncState == DataStoreSyncState.NONE_REQUESTED - - } - } - and: 'event service is called to publish event' - 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) - } - - def 'Update cmHandle state to "DELETING"' (){ - given: 'cm Handle as Yang model' - compositeState = new CompositeState(cmHandleState: READY) - yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) - when: 'updating cm handle state to "DELETING"' - objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETING) - then: 'the cm handle state is as expected' - yangModelCmHandle.getCompositeState().getCmHandleState() == DELETING - and: 'method to persist cm handle state is called once' - 1 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()) - and: 'the method to publish Lcm event is called once' - 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) - } - - def 'Update cmHandle state to "DELETED"' (){ - given: 'cm Handle with state "DELETING" as Yang model ' - compositeState = new CompositeState(cmHandleState: DELETING) - yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) - when: 'updating cm handle state to "DELETED"' - objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETED) - then: 'the cm handle state is as expected' - yangModelCmHandle.getCompositeState().getCmHandleState() == DELETED - and: 'the method to publish Lcm event is called once' - 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) - } - - def 'No state change and no event to be published'() { - given: 'Cm Handle batch with same state transition as before' - def cmHandleStateMap = setupBatch('NO_CHANGE') - when: 'updating a batch of changes' - objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap) - then: 'batch is empty and nothing to update' - 1 * mockInventoryPersistence.saveCmHandleBatch(_) >> { - args -> { - assert (args[0] as Collection).size() == 0 - } - } - and: 'no event will be published' - 0 * mockLcmEventsService.publishLcmEvent(*_) - } - - def 'Batch of new cm handles provided'() { - given: 'A batch of new cm handles' - def cmHandleStateMap = setupBatch('NEW') - when: 'updating a batch of changes' - objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap) - then: 'new cm handles are saved using inventory persistence' - 1 * mockInventoryPersistence.saveCmHandleBatch(_) >> { - args -> { - assert (args[0] as Collection).id.containsAll('cmhandle1', 'cmhandle2') - } - } - and: 'event service is called to publish event' - 2 * mockLcmEventsService.publishLcmEvent(_, _) - - } - - def 'Batch of existing cm handles is updated'() { - given: 'A batch of updated cm handles' - def cmHandleStateMap = setupBatch('UPDATE') - when: 'updating a batch of changes' - objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap) - then : 'existing cm handles composite state is persisted' - 1 * mockInventoryPersistence.saveCmHandleStateBatch(_) >> { - args -> { - assert (args[0] as Map).keySet().containsAll(['cmhandle1','cmhandle2']) - } - } - and: 'event service is called to publish event' - 2 * mockLcmEventsService.publishLcmEvent(_, _) - - } - - def setupBatch(type) { - - def yangModelCmHandle1 = new YangModelCmHandle(id: 'cmhandle1', dmiProperties: [], publicProperties: []) - def yangModelCmHandle2 = new YangModelCmHandle(id: 'cmhandle2', dmiProperties: [], publicProperties: []) - - if ('NEW' == type) { - return [(yangModelCmHandle1): ADVISED, (yangModelCmHandle2): ADVISED] - } - - if ('UPDATE' == type) { - yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: ADVISED) - yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY) - return [(yangModelCmHandle1): READY, (yangModelCmHandle2): DELETING] - } - - if ('NO_CHANGE' == type) { - yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: ADVISED) - yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY) - return [(yangModelCmHandle1): ADVISED, (yangModelCmHandle2): READY] - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorSpec.groovy deleted file mode 100644 index 7b8b2b453..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCreatorSpec.groovy +++ /dev/null @@ -1,162 +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.event.lcm - -import org.onap.cps.ncmp.api.inventory.CmHandleState -import org.onap.cps.ncmp.api.inventory.CompositeState -import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle -import org.onap.ncmp.cmhandle.event.lcm.Values -import spock.lang.Specification - -import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED -import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETING -import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY - -class LcmEventsCreatorSpec extends Specification { - - def objectUnderTest = new LcmEventsCreator() - def cmHandleId = 'test-cm-handle' - - def 'Map the LcmEvent for #operation'() { - given: 'NCMP cm handle details with current and old properties' - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: existingCmHandleState), - publicProperties: existingPublicProperties) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: targetCmHandleState), - publicProperties: targetPublicProperties) - when: 'the event is populated' - def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) - then: 'event header is mapped correctly' - assert result.eventSource == 'org.onap.ncmp' - assert result.eventCorrelationId == cmHandleId - assert result.eventType == LcmEventType.UPDATE.eventType - and: 'event payload is mapped correctly with correct cmhandle id' - assert result.event.cmHandleId == cmHandleId - and: 'it should have correct old state and properties' - assert result.event.oldValues.cmHandleState == expectedExistingCmHandleState - assert result.event.oldValues.cmHandleProperties == [expectedExistingPublicProperties] - and: 'the correct new state and properties' - assert result.event.newValues.cmHandleProperties == [expectedTargetPublicProperties] - assert result.event.newValues.cmHandleState == expectedTargetCmHandleState - where: 'following parameters are provided' - operation | existingCmHandleState | targetCmHandleState | existingPublicProperties | targetPublicProperties || expectedExistingPublicProperties | expectedTargetPublicProperties | expectedExistingCmHandleState | expectedTargetCmHandleState - 'UPDATE' | ADVISED | READY | ['publicProperty1': 'value1', 'publicProperty2': 'value2'] | ['publicProperty1': 'value11'] || ['publicProperty1': 'value1', 'publicProperty2': 'value2'] | ['publicProperty1': 'value11'] | Values.CmHandleState.ADVISED | Values.CmHandleState.READY - 'DELETING' | READY | DELETING | ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] || ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] | Values.CmHandleState.READY | Values.CmHandleState.DELETING - 'CHANGE' | READY | READY | ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] || ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] | null | null - } - - def 'Map the LcmEvent for all properties NO CHANGE'() { - given: 'NCMP cm handle details without any changes' - def publicProperties = ['publicProperty1': 'value3', 'publicProperty2': 'value4'] - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: READY), - publicProperties: publicProperties) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: READY), - publicProperties: publicProperties) - when: 'the event is populated' - def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) - then: 'Properties are just the one which are same' - assert result.event.oldValues == null - assert result.event.newValues == null - } - - def 'Map the LcmEvent for operation CREATE'() { - given: 'NCMP cm handle details' - def targetNcmpServiceCmhandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: READY), - publicProperties: ['publicProperty1': 'value11', 'publicProperty2': 'value22']) - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProperty1': 'value1', 'publicProperty2': 'value2']) - when: 'the event is populated' - def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmhandle, existingNcmpServiceCmHandle) - then: 'event header is mapped correctly' - assert result.eventSource == 'org.onap.ncmp' - assert result.eventCorrelationId == cmHandleId - assert result.eventType == LcmEventType.CREATE.eventType - and: 'event payload is mapped correctly' - assert result.event.cmHandleId == cmHandleId - assert result.event.newValues.cmHandleState == Values.CmHandleState.READY - assert result.event.newValues.dataSyncEnabled == false - assert result.event.newValues.cmHandleProperties == [['publicProperty1': 'value11', 'publicProperty2': 'value22']] - and: 'it should not have any old values' - assert result.event.oldValues == null - } - - def 'Map the LcmEvent for DELETE operation'() { - given: 'NCMP cm handle details' - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: CmHandleState.DELETED), - publicProperties: ['publicProperty1': 'value11', 'publicProperty2': 'value22']) - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: DELETING), - publicProperties: ['publicProperty1': 'value1']) - when: 'the event is populated' - def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) - then: 'event header is mapped correctly' - assert result.eventSource == 'org.onap.ncmp' - assert result.eventCorrelationId == cmHandleId - assert result.eventType == LcmEventType.DELETE.eventType - and: 'event payload is mapped correctly ' - assert result.event.cmHandleId == cmHandleId - assert result.event.oldValues == null - assert result.event.newValues == null - } - - def 'Map the LcmEvent for datasync flag transition from #operation'() { - given: 'NCMP cm handle details with current and old details' - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: existingDataSyncEnableFlag, cmHandleState: ADVISED)) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: targetDataSyncEnableFlag, cmHandleState: READY)) - when: 'the event is populated' - def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) - then: 'event header is mapped correctly' - assert result.eventSource == 'org.onap.ncmp' - assert result.eventCorrelationId == cmHandleId - assert result.eventType == LcmEventType.UPDATE.eventType - and: 'event payload is mapped correctly with correct cmhandle id' - assert result.event.cmHandleId == cmHandleId - and: 'it should have correct old values' - assert result.event.oldValues.cmHandleState == Values.CmHandleState.ADVISED - assert result.event.oldValues.dataSyncEnabled == existingDataSyncEnableFlag - and: 'the correct new values' - assert result.event.newValues.cmHandleState == Values.CmHandleState.READY - assert result.event.newValues.dataSyncEnabled == targetDataSyncEnableFlag - where: 'following parameters are provided' - operation | existingDataSyncEnableFlag | targetDataSyncEnableFlag - 'false to true' | false | true - 'false to null' | false | null - 'true to false' | true | false - 'true to null' | true | null - 'null to true' | null | true - 'null to false' | null | false - - } - - def 'Map the LcmEvent for datasync flag for same transition from #operation'() { - given: 'NCMP cm handle details with current and old details' - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: existingDataSyncEnableFlag, cmHandleState: ADVISED)) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: targetDataSyncEnableFlag, cmHandleState: READY)) - when: 'the event is populated' - def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) - then: 'the data sync flag is not present in the event' - assert result.event.oldValues.dataSyncEnabled == null - assert result.event.newValues.dataSyncEnabled == null - where: 'following parameters are provided' - operation | existingDataSyncEnableFlag | targetDataSyncEnableFlag - 'false to false' | false | false - 'true to true' | true | true - 'null to null' | null | null - - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsPublisherSpec.groovy deleted file mode 100644 index f5b58a753..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsPublisherSpec.groovy +++ /dev/null @@ -1,83 +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.event.lcm - -import com.fasterxml.jackson.databind.ObjectMapper -import org.apache.kafka.clients.consumer.KafkaConsumer -import org.onap.cps.ncmp.api.impl.event.EventsPublisher -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.onap.ncmp.cmhandle.event.lcm.Event -import org.onap.ncmp.cmhandle.event.lcm.LcmEvent -import org.spockframework.spring.SpringBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.annotation.DirtiesContext -import org.testcontainers.spock.Testcontainers - -import java.time.Duration - -@SpringBootTest(classes = [EventsPublisher, ObjectMapper, JsonObjectMapper]) -@Testcontainers -@DirtiesContext -class LcmEventsPublisherSpec extends MessagingBaseSpec { - - def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group')) - - def testTopic = 'ncmp-events-test' - - @SpringBean - EventsPublisher lcmEventsPublisher = new EventsPublisher(kafkaTemplate) - - @Autowired - JsonObjectMapper jsonObjectMapper - - - def 'Produce and Consume Lcm Event'() { - given: 'event key and event data' - def eventKey = 'lcm' - def eventData = new LcmEvent( - eventId: 'test-uuid', - eventCorrelationId: 'cmhandle-as-correlationid', - eventSource: 'org.onap.ncmp', - eventTime: '2022-12-31T20:30:40.000+0000', - eventType: 'org.onap.ncmp.cmhandle.lcm.event', - eventSchema: 'org.onap.ncmp.cmhandle.lcm.event', - eventSchemaVersion: 'v1', - event: new Event(cmHandleId: 'cmhandle-test')) - and: 'consumer has a subscription' - kafkaConsumer.subscribe([testTopic] as List) - when: 'an event is published' - lcmEventsPublisher.publishEvent(testTopic, eventKey, eventData) - and: 'topic is polled' - def records = kafkaConsumer.poll(Duration.ofMillis(1500)) - then: 'poll returns one record' - assert records.size() == 1 - and: 'record key matches the expected event key' - def record = records.iterator().next() - assert eventKey == record.key - and: 'record matches the expected event' - def expectedJsonString = TestUtils.getResourceFileContent('expectedLcmEvent.json') - def expectedLcmEvent = jsonObjectMapper.convertJsonString(expectedJsonString, LcmEvent.class) - assert expectedLcmEvent == jsonObjectMapper.convertJsonString(record.value, LcmEvent.class) - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsServiceSpec.groovy deleted file mode 100644 index 4c632ddf0..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsServiceSpec.groovy +++ /dev/null @@ -1,63 +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.event.lcm - -import org.onap.cps.ncmp.api.impl.event.EventsPublisher -import org.onap.ncmp.cmhandle.event.lcm.LcmEvent -import org.springframework.kafka.KafkaException -import spock.lang.Specification - -class LcmEventsServiceSpec extends Specification { - - def mockLcmEventsPublisher = Mock(EventsPublisher) - - def objectUnderTest = new LcmEventsService(mockLcmEventsPublisher) - - def 'Create and Publish lcm event where events are #scenario'() { - given: 'a cm handle id and Lcm Event' - def cmHandleId = 'test-cm-handle-id' - def lcmEvent = new LcmEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) - and: 'notificationsEnabled is #notificationsEnabled and it will be true as default' - objectUnderTest.notificationsEnabled = notificationsEnabled - when: 'service is called to publish lcm event' - objectUnderTest.publishLcmEvent('test-cm-handle-id', lcmEvent) - then: 'publisher is called #expectedTimesMethodCalled times' - expectedTimesMethodCalled * mockLcmEventsPublisher.publishEvent(_, cmHandleId, lcmEvent) - where: 'the following values are used' - scenario | notificationsEnabled || expectedTimesMethodCalled - 'enabled' | true || 1 - 'disabled' | false || 0 - } - - def 'Unable to send message'(){ - given: 'a cm handle id and Lcm Event and notification enabled' - def cmHandleId = 'test-cm-handle-id' - def lcmEvent = new LcmEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) - objectUnderTest.notificationsEnabled = true - when: 'publisher set to throw an exception' - mockLcmEventsPublisher.publishEvent(*_) >> { throw new KafkaException('publishing failed')} - and: 'an event is publised' - objectUnderTest.publishLcmEvent(cmHandleId, lcmEvent) - then: 'the exception is just logged and not bubbled up' - noExceptionThrown() - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducerIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducerIntegrationSpec.groovy new file mode 100644 index 000000000..64d1f64e5 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventProducerIntegrationSpec.groovy @@ -0,0 +1,84 @@ +/* + * ============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.avc + +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.kafka.clients.consumer.KafkaConsumer +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.event.model.AvcEvent +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 org.springframework.test.annotation.DirtiesContext +import org.testcontainers.spock.Testcontainers + +import java.time.Duration + +@SpringBootTest(classes = [AvcEventProducer, AvcEventConsumer, ObjectMapper, JsonObjectMapper]) +@Testcontainers +@DirtiesContext +class AvcEventProducerIntegrationSpec extends MessagingBaseSpec { + + @SpringBean + AvcEventMapper avcEventMapper = Mappers.getMapper(AvcEventMapper.class) + + @SpringBean + AvcEventProducer avcEventProducer = new AvcEventProducer(kafkaTemplate, avcEventMapper) + + @SpringBean + AvcEventConsumer acvEventConsumer = new AvcEventConsumer(avcEventProducer) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group')) + + def 'Consume and forward valid message'() { + given: 'consumer has a subscription on a topic' + def cmEventsTopic = 'cm-events' + avcEventProducer.cmEventsTopic = cmEventsTopic + kafkaConsumer.subscribe([cmEventsTopic] as List) + and: 'an event is sent' + def jsonData = TestUtils.getResourceFileContent('sampleAvcInputEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, AvcEvent.class) + when: 'the event is consumed' + acvEventConsumer.consumeAndForward(testEventSent) + and: 'the topic is polled' + def records = kafkaConsumer.poll(Duration.ofMillis(1500)) + then: 'poll returns one record' + assert records.size() == 1 + and: 'record can be converted to AVC event' + def record = records.iterator().next() + def convertedAvcEvent = jsonObjectMapper.convertJsonString(record.value(), AvcEvent) + and: 'consumed forwarded NCMP event id differs from DMI event id' + assert testEventSent.eventId != convertedAvcEvent.getEventId() + and: 'correlation id matches' + assert testEventSent.eventCorrelationId == convertedAvcEvent.getEventCorrelationId() + and: 'timestamps match' + assert testEventSent.eventTime == convertedAvcEvent.getEventTime() + and: 'target matches' + assert testEventSent.eventSource == convertedAvcEvent.getEventSource() + } + +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionCreateProducerDemo.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionCreateProducerDemo.groovy new file mode 100644 index 000000000..54a7ad333 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionCreateProducerDemo.groovy @@ -0,0 +1,57 @@ +/* + * ============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.avc + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.event.model.SubscriptionEvent +import org.onap.cps.ncmp.utils.KafkaDemoProducerConfig +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.kafka.core.KafkaTemplate +import org.springframework.test.annotation.DirtiesContext +import spock.lang.Specification + +@SpringBootTest(classes = [KafkaDemoProducerConfig, ObjectMapper, JsonObjectMapper]) +@DirtiesContext +class SubscriptionCreateProducerDemo extends Specification { + + @Value('${app.ncmp.avc.subscription-topic}') + String subscriptionTopic; + + @Autowired + KafkaTemplate kafkaTemplate + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'produce subscription creation data event for testing'() { + given: 'avc subscription creation event data' + def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) + and: 'test event is sent' + kafkaTemplate.send(subscriptionTopic, "request-Id-98765", testEventSent); + and: 'print json data to console' + println(jsonData); + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy new file mode 100644 index 000000000..3a7aa481c --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy @@ -0,0 +1,63 @@ +/* + * ============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.avc + +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.event.model.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: 'client 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 + } + +} \ No newline at end of file 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 new file mode 100644 index 000000000..243c31b39 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventConsumerSpec.groovy @@ -0,0 +1,113 @@ +/* + * ============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 org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.event.model.SubscriptionEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.spi.exceptions.OperationNotYetSupportedException +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 objectUnderTest = new SubscriptionEventConsumer(mockSubscriptionEventForwarder, mockSubscriptionEventMapper, mockSubscriptionPersistence) + + def yangModelSubscriptionEvent = new YangModelSubscriptionEvent() + + @Autowired + JsonObjectMapper jsonObjectMapper + + 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) + and: 'notifications are enabled' + objectUnderTest.notificationFeatureEnabled = true + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = true + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(testEventSent) + then: 'the event is mapped to a yangModelSubscription' + 1 * mockSubscriptionEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent + and: 'the event is persisted' + 1 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) + and: 'the event is forwarded' + 1 * mockSubscriptionEventForwarder.forwardCreateSubscriptionEvent(testEventSent) + } + + def 'Consume valid CM create message where notifications and model loader are disabled'() { + given: 'an event with data category CM' + def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) + and: 'notifications are disabled' + objectUnderTest.notificationFeatureEnabled = false + and: 'subscription model loader is disabled' + objectUnderTest.subscriptionModelLoaderEnabled = false + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(testEventSent) + then: 'the event is not mapped to a yangModelSubscription' + 0 * mockSubscriptionEventMapper.toYangModelSubscriptionEvent(*_) >> yangModelSubscriptionEvent + and: 'the event is not persisted' + 0 * mockSubscriptionPersistence.saveSubscriptionEvent(*_) + and: 'the event is not forwarded' + 0 * mockSubscriptionEventForwarder.forwardCreateSubscriptionEvent(*_) + } + + def 'Consume valid FM message'() { + given: 'an event' + def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) + and: 'dataCategory is set to FM' + testEventSent.getEvent().getDataType().setDataCategory("FM") + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(testEventSent) + then: 'no exception is thrown' + noExceptionThrown() + and: 'the event is not mapped to a yangModelSubscription' + 0 * mockSubscriptionEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent + and: 'the event is not persisted' + 0 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) + and: 'No event is forwarded' + 0 * mockSubscriptionEventForwarder.forwardCreateSubscriptionEvent(*_) + } + + 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 non passthrough datastore' + testEventSent.getEvent().getPredicates().setDatastore("operational") + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(testEventSent) + then: 'an operation not yet supported exception is thrown' + thrown(OperationNotYetSupportedException) + } + +} 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 new file mode 100644 index 000000000..2b0adf342 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy @@ -0,0 +1,94 @@ +/* + * ============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.onap.cps.ncmp.api.impl.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.inventory.InventoryPersistence +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.event.model.SubscriptionEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.spi.exceptions.OperationNotYetSupportedException +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 SubscriptionEventForwarderSpec extends MessagingBaseSpec { + + def mockInventoryPersistence = Mock(InventoryPersistence) + def mockSubscriptionEventPublisher = Mock(EventsPublisher) + def objectUnderTest = new SubscriptionEventForwarder(mockInventoryPersistence, mockSubscriptionEventPublisher) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Forward valid CM create subscription'() { + 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"), + createYangModelCmHandleWithDmiProperty(3, 2,"shape","triangle") + ] + when: 'the valid event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(testEventSent) + then: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' + 1 * mockSubscriptionEventPublisher.publishEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", + subscriptionEvent -> { + Map targets = subscriptionEvent.getEvent().getPredicates().getTargets().get(0) + targets["CMHandle1"] == ["shape":"circle"] + targets["CMHandle2"] == ["shape":"square"] + } + ) + 1 * mockSubscriptionEventPublisher.publishEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", + subscriptionEvent -> { + Map targets = subscriptionEvent.getEvent().getPredicates().getTargets().get(0) + targets["CMHandle3"] == ["shape":"triangle"] + } + ) + } + + 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.getEvent().getPredicates().setTargets(invalidTargets) + when: 'the event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(testEventSent) + then: 'an operation not yet supported exception is thrown' + thrown(OperationNotYetSupportedException) + where: + scenario | invalidTargets + 'null' | null + 'empty' | [] + 'wildcard' | ['CMHandle*'] + } + + static def createYangModelCmHandleWithDmiProperty(id, dmiId,propertyName, propertyValue) { + return new YangModelCmHandle(id:"CMHandle" + id, dmiDataServiceName: "DMIName" + dmiId, dmiProperties: [new YangModelCmHandle.Property(propertyName,propertyValue)]) + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy new file mode 100644 index 000000000..f660be710 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy @@ -0,0 +1,211 @@ +/* + * ============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.lcm + +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.inventory.CompositeState +import org.onap.cps.ncmp.api.inventory.DataStoreSyncState +import org.onap.cps.ncmp.api.inventory.InventoryPersistence +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETING +import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED +import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY +import static org.onap.cps.ncmp.api.inventory.LockReasonCategory.LOCKED_MODULE_SYNC_FAILED + +class LcmEventsCmHandleStateHandlerImplSpec extends Specification { + + def mockInventoryPersistence = Mock(InventoryPersistence) + def mockLcmEventsCreator = Mock(LcmEventsCreator) + def mockLcmEventsService = Mock(LcmEventsService) + + def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, mockLcmEventsCreator, mockLcmEventsService) + + def cmHandleId = 'cmhandle-id-1' + def compositeState + def yangModelCmHandle + + def 'Update and Publish Events on State Change #stateChange'() { + given: 'Cm Handle represented as YangModelCmHandle' + compositeState = new CompositeState(cmHandleState: fromCmHandleState) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + when: 'update state is invoked' + objectUnderTest.updateCmHandleState(yangModelCmHandle, toCmHandleState) + then: 'state is saved using inventory persistence' + expectedCallsToInventoryPersistence * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) + and: 'event service is called to publish event' + expectedCallsToEventService * mockLcmEventsService.publishLcmEvent(cmHandleId, _) + where: 'state change parameters are provided' + stateChange | fromCmHandleState | toCmHandleState || expectedCallsToInventoryPersistence | expectedCallsToEventService + 'ADVISED to READY' | ADVISED | READY || 1 | 1 + 'READY to LOCKED' | READY | LOCKED || 1 | 1 + 'ADVISED to ADVISED' | ADVISED | ADVISED || 0 | 0 + 'READY to READY' | READY | READY || 0 | 0 + 'LOCKED to LOCKED' | LOCKED | LOCKED || 0 | 0 + + } + + def 'Update and Publish Events on State Change from NO_EXISTING state to ADVISED'() { + given: 'Cm Handle represented as YangModelCmHandle' + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: []) + when: 'update state is invoked' + objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) + then: 'state is saved using inventory persistence' + 1 * mockInventoryPersistence.saveCmHandle(yangModelCmHandle) + and: 'event service is called to publish event' + 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) + } + + def 'Update and Publish Events on State Change from LOCKED to ADVISED'() { + given: 'Cm Handle represented as YangModelCmHandle in LOCKED state' + compositeState = new CompositeState(cmHandleState: LOCKED, + lockReason: CompositeState.LockReason.builder().lockReasonCategory(LOCKED_MODULE_SYNC_FAILED).details('some lock details').build()) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + when: 'update state is invoked' + objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) + then: 'state is saved using inventory persistence and old lock reason details are retained' + 1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> { + args -> { + assert (args[1] as CompositeState).lockReason.details == 'some lock details' + } + } + and: 'event service is called to publish event' + 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) + } + + def 'Update and Publish Events on State Change to READY'() { + given: 'Cm Handle represented as YangModelCmHandle' + compositeState = new CompositeState(cmHandleState: ADVISED) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + and: 'global sync flag is set' + compositeState.setDataSyncEnabled(false) + when: 'update cmhandle state is invoked' + objectUnderTest.updateCmHandleState(yangModelCmHandle, READY) + then: 'state is saved using inventory persistence with expected dataSyncState' + 1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> { + args-> { + def result = (args[1] as CompositeState) + assert result.dataSyncEnabled == false + assert result.dataStores.operationalDataStore.dataStoreSyncState == DataStoreSyncState.NONE_REQUESTED + + } + } + and: 'event service is called to publish event' + 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) + } + + def 'Update cmHandle state to "DELETING"' (){ + given: 'cm Handle as Yang model' + compositeState = new CompositeState(cmHandleState: READY) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + when: 'updating cm handle state to "DELETING"' + objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETING) + then: 'the cm handle state is as expected' + yangModelCmHandle.getCompositeState().getCmHandleState() == DELETING + and: 'method to persist cm handle state is called once' + 1 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()) + and: 'the method to publish Lcm event is called once' + 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) + } + + def 'Update cmHandle state to "DELETED"' (){ + given: 'cm Handle with state "DELETING" as Yang model ' + compositeState = new CompositeState(cmHandleState: DELETING) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + when: 'updating cm handle state to "DELETED"' + objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETED) + then: 'the cm handle state is as expected' + yangModelCmHandle.getCompositeState().getCmHandleState() == DELETED + and: 'the method to publish Lcm event is called once' + 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) + } + + def 'No state change and no event to be published'() { + given: 'Cm Handle batch with same state transition as before' + def cmHandleStateMap = setupBatch('NO_CHANGE') + when: 'updating a batch of changes' + objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap) + then: 'batch is empty and nothing to update' + 1 * mockInventoryPersistence.saveCmHandleBatch(_) >> { + args -> { + assert (args[0] as Collection).size() == 0 + } + } + and: 'no event will be published' + 0 * mockLcmEventsService.publishLcmEvent(*_) + } + + def 'Batch of new cm handles provided'() { + given: 'A batch of new cm handles' + def cmHandleStateMap = setupBatch('NEW') + when: 'updating a batch of changes' + objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap) + then: 'new cm handles are saved using inventory persistence' + 1 * mockInventoryPersistence.saveCmHandleBatch(_) >> { + args -> { + assert (args[0] as Collection).id.containsAll('cmhandle1', 'cmhandle2') + } + } + and: 'event service is called to publish event' + 2 * mockLcmEventsService.publishLcmEvent(_, _) + + } + + def 'Batch of existing cm handles is updated'() { + given: 'A batch of updated cm handles' + def cmHandleStateMap = setupBatch('UPDATE') + when: 'updating a batch of changes' + objectUnderTest.updateCmHandleStateBatch(cmHandleStateMap) + then : 'existing cm handles composite state is persisted' + 1 * mockInventoryPersistence.saveCmHandleStateBatch(_) >> { + args -> { + assert (args[0] as Map).keySet().containsAll(['cmhandle1','cmhandle2']) + } + } + and: 'event service is called to publish event' + 2 * mockLcmEventsService.publishLcmEvent(_, _) + + } + + def setupBatch(type) { + + def yangModelCmHandle1 = new YangModelCmHandle(id: 'cmhandle1', dmiProperties: [], publicProperties: []) + def yangModelCmHandle2 = new YangModelCmHandle(id: 'cmhandle2', dmiProperties: [], publicProperties: []) + + if ('NEW' == type) { + return [(yangModelCmHandle1): ADVISED, (yangModelCmHandle2): ADVISED] + } + + if ('UPDATE' == type) { + yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: ADVISED) + yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY) + return [(yangModelCmHandle1): READY, (yangModelCmHandle2): DELETING] + } + + if ('NO_CHANGE' == type) { + yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: ADVISED) + yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY) + return [(yangModelCmHandle1): ADVISED, (yangModelCmHandle2): READY] + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy new file mode 100644 index 000000000..f4adfc587 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy @@ -0,0 +1,162 @@ +/* + * ============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.lcm + +import org.onap.cps.ncmp.api.inventory.CmHandleState +import org.onap.cps.ncmp.api.inventory.CompositeState +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle +import org.onap.ncmp.cmhandle.event.lcm.Values +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETING +import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY + +class LcmEventsCreatorSpec extends Specification { + + def objectUnderTest = new LcmEventsCreator() + def cmHandleId = 'test-cm-handle' + + def 'Map the LcmEvent for #operation'() { + given: 'NCMP cm handle details with current and old properties' + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: existingCmHandleState), + publicProperties: existingPublicProperties) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: targetCmHandleState), + publicProperties: targetPublicProperties) + when: 'the event is populated' + def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) + then: 'event header is mapped correctly' + assert result.eventSource == 'org.onap.ncmp' + assert result.eventCorrelationId == cmHandleId + assert result.eventType == LcmEventType.UPDATE.eventType + and: 'event payload is mapped correctly with correct cmhandle id' + assert result.event.cmHandleId == cmHandleId + and: 'it should have correct old state and properties' + assert result.event.oldValues.cmHandleState == expectedExistingCmHandleState + assert result.event.oldValues.cmHandleProperties == [expectedExistingPublicProperties] + and: 'the correct new state and properties' + assert result.event.newValues.cmHandleProperties == [expectedTargetPublicProperties] + assert result.event.newValues.cmHandleState == expectedTargetCmHandleState + where: 'following parameters are provided' + operation | existingCmHandleState | targetCmHandleState | existingPublicProperties | targetPublicProperties || expectedExistingPublicProperties | expectedTargetPublicProperties | expectedExistingCmHandleState | expectedTargetCmHandleState + 'UPDATE' | ADVISED | READY | ['publicProperty1': 'value1', 'publicProperty2': 'value2'] | ['publicProperty1': 'value11'] || ['publicProperty1': 'value1', 'publicProperty2': 'value2'] | ['publicProperty1': 'value11'] | Values.CmHandleState.ADVISED | Values.CmHandleState.READY + 'DELETING' | READY | DELETING | ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] || ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] | Values.CmHandleState.READY | Values.CmHandleState.DELETING + 'CHANGE' | READY | READY | ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] || ['publicProperty1': 'value3', 'publicProperty2': 'value4'] | ['publicProperty1': 'value33'] | null | null + } + + def 'Map the LcmEvent for all properties NO CHANGE'() { + given: 'NCMP cm handle details without any changes' + def publicProperties = ['publicProperty1': 'value3', 'publicProperty2': 'value4'] + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: READY), + publicProperties: publicProperties) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: READY), + publicProperties: publicProperties) + when: 'the event is populated' + def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) + then: 'Properties are just the one which are same' + assert result.event.oldValues == null + assert result.event.newValues == null + } + + def 'Map the LcmEvent for operation CREATE'() { + given: 'NCMP cm handle details' + def targetNcmpServiceCmhandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: READY), + publicProperties: ['publicProperty1': 'value11', 'publicProperty2': 'value22']) + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProperty1': 'value1', 'publicProperty2': 'value2']) + when: 'the event is populated' + def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmhandle, existingNcmpServiceCmHandle) + then: 'event header is mapped correctly' + assert result.eventSource == 'org.onap.ncmp' + assert result.eventCorrelationId == cmHandleId + assert result.eventType == LcmEventType.CREATE.eventType + and: 'event payload is mapped correctly' + assert result.event.cmHandleId == cmHandleId + assert result.event.newValues.cmHandleState == Values.CmHandleState.READY + assert result.event.newValues.dataSyncEnabled == false + assert result.event.newValues.cmHandleProperties == [['publicProperty1': 'value11', 'publicProperty2': 'value22']] + and: 'it should not have any old values' + assert result.event.oldValues == null + } + + def 'Map the LcmEvent for DELETE operation'() { + given: 'NCMP cm handle details' + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: CmHandleState.DELETED), + publicProperties: ['publicProperty1': 'value11', 'publicProperty2': 'value22']) + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: DELETING), + publicProperties: ['publicProperty1': 'value1']) + when: 'the event is populated' + def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) + then: 'event header is mapped correctly' + assert result.eventSource == 'org.onap.ncmp' + assert result.eventCorrelationId == cmHandleId + assert result.eventType == LcmEventType.DELETE.eventType + and: 'event payload is mapped correctly ' + assert result.event.cmHandleId == cmHandleId + assert result.event.oldValues == null + assert result.event.newValues == null + } + + def 'Map the LcmEvent for datasync flag transition from #operation'() { + given: 'NCMP cm handle details with current and old details' + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: existingDataSyncEnableFlag, cmHandleState: ADVISED)) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: targetDataSyncEnableFlag, cmHandleState: READY)) + when: 'the event is populated' + def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) + then: 'event header is mapped correctly' + assert result.eventSource == 'org.onap.ncmp' + assert result.eventCorrelationId == cmHandleId + assert result.eventType == LcmEventType.UPDATE.eventType + and: 'event payload is mapped correctly with correct cmhandle id' + assert result.event.cmHandleId == cmHandleId + and: 'it should have correct old values' + assert result.event.oldValues.cmHandleState == Values.CmHandleState.ADVISED + assert result.event.oldValues.dataSyncEnabled == existingDataSyncEnableFlag + and: 'the correct new values' + assert result.event.newValues.cmHandleState == Values.CmHandleState.READY + assert result.event.newValues.dataSyncEnabled == targetDataSyncEnableFlag + where: 'following parameters are provided' + operation | existingDataSyncEnableFlag | targetDataSyncEnableFlag + 'false to true' | false | true + 'false to null' | false | null + 'true to false' | true | false + 'true to null' | true | null + 'null to true' | null | true + 'null to false' | null | false + + } + + def 'Map the LcmEvent for datasync flag for same transition from #operation'() { + given: 'NCMP cm handle details with current and old details' + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: existingDataSyncEnableFlag, cmHandleState: ADVISED)) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: targetDataSyncEnableFlag, cmHandleState: READY)) + when: 'the event is populated' + def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) + then: 'the data sync flag is not present in the event' + assert result.event.oldValues.dataSyncEnabled == null + assert result.event.newValues.dataSyncEnabled == null + where: 'following parameters are provided' + operation | existingDataSyncEnableFlag | targetDataSyncEnableFlag + 'false to false' | false | false + 'true to true' | true | true + 'null to null' | null | null + + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy new file mode 100644 index 000000000..7c9464dcc --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy @@ -0,0 +1,83 @@ +/* + * ============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.lcm + +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.kafka.clients.consumer.KafkaConsumer +import org.onap.cps.ncmp.api.impl.events.EventsPublisher +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.onap.ncmp.cmhandle.event.lcm.Event +import org.onap.ncmp.cmhandle.event.lcm.LcmEvent +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.annotation.DirtiesContext +import org.testcontainers.spock.Testcontainers + +import java.time.Duration + +@SpringBootTest(classes = [EventsPublisher, ObjectMapper, JsonObjectMapper]) +@Testcontainers +@DirtiesContext +class LcmEventsPublisherSpec extends MessagingBaseSpec { + + def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group')) + + def testTopic = 'ncmp-events-test' + + @SpringBean + EventsPublisher lcmEventsPublisher = new EventsPublisher(kafkaTemplate) + + @Autowired + JsonObjectMapper jsonObjectMapper + + + def 'Produce and Consume Lcm Event'() { + given: 'event key and event data' + def eventKey = 'lcm' + def eventData = new LcmEvent( + eventId: 'test-uuid', + eventCorrelationId: 'cmhandle-as-correlationid', + eventSource: 'org.onap.ncmp', + eventTime: '2022-12-31T20:30:40.000+0000', + eventType: 'org.onap.ncmp.cmhandle.lcm.event', + eventSchema: 'org.onap.ncmp.cmhandle.lcm.event', + eventSchemaVersion: 'v1', + event: new Event(cmHandleId: 'cmhandle-test')) + and: 'consumer has a subscription' + kafkaConsumer.subscribe([testTopic] as List) + when: 'an event is published' + lcmEventsPublisher.publishEvent(testTopic, eventKey, eventData) + and: 'topic is polled' + def records = kafkaConsumer.poll(Duration.ofMillis(1500)) + then: 'poll returns one record' + assert records.size() == 1 + and: 'record key matches the expected event key' + def record = records.iterator().next() + assert eventKey == record.key + and: 'record matches the expected event' + def expectedJsonString = TestUtils.getResourceFileContent('expectedLcmEvent.json') + def expectedLcmEvent = jsonObjectMapper.convertJsonString(expectedJsonString, LcmEvent.class) + assert expectedLcmEvent == jsonObjectMapper.convertJsonString(record.value, LcmEvent.class) + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy new file mode 100644 index 000000000..65f4d50c6 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy @@ -0,0 +1,63 @@ +/* + * ============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.lcm + +import org.onap.cps.ncmp.api.impl.events.EventsPublisher +import org.onap.ncmp.cmhandle.event.lcm.LcmEvent +import org.springframework.kafka.KafkaException +import spock.lang.Specification + +class LcmEventsServiceSpec extends Specification { + + def mockLcmEventsPublisher = Mock(EventsPublisher) + + def objectUnderTest = new LcmEventsService(mockLcmEventsPublisher) + + def 'Create and Publish lcm event where events are #scenario'() { + given: 'a cm handle id and Lcm Event' + def cmHandleId = 'test-cm-handle-id' + def lcmEvent = new LcmEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) + and: 'notificationsEnabled is #notificationsEnabled and it will be true as default' + objectUnderTest.notificationsEnabled = notificationsEnabled + when: 'service is called to publish lcm event' + objectUnderTest.publishLcmEvent('test-cm-handle-id', lcmEvent) + then: 'publisher is called #expectedTimesMethodCalled times' + expectedTimesMethodCalled * mockLcmEventsPublisher.publishEvent(_, cmHandleId, lcmEvent) + where: 'the following values are used' + scenario | notificationsEnabled || expectedTimesMethodCalled + 'enabled' | true || 1 + 'disabled' | false || 0 + } + + def 'Unable to send message'(){ + given: 'a cm handle id and Lcm Event and notification enabled' + def cmHandleId = 'test-cm-handle-id' + def lcmEvent = new LcmEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) + objectUnderTest.notificationsEnabled = true + when: 'publisher set to throw an exception' + mockLcmEventsPublisher.publishEvent(*_) >> { throw new KafkaException('publishing failed')} + and: 'an event is publised' + objectUnderTest.publishLcmEvent(cmHandleId, lcmEvent) + then: 'the exception is just logged and not bubbled up' + noExceptionThrown() + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy deleted file mode 100644 index a251ecbf0..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy +++ /dev/null @@ -1,85 +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.notifications.avc - -import com.fasterxml.jackson.databind.ObjectMapper -import org.apache.kafka.clients.consumer.KafkaConsumer -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.async.NcmpAsyncRequestResponseEventMapper -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.event.model.AvcEvent -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 org.springframework.test.annotation.DirtiesContext -import org.testcontainers.spock.Testcontainers - -import java.time.Duration - -@SpringBootTest(classes = [AvcEventProducer, AvcEventConsumer, ObjectMapper, JsonObjectMapper]) -@Testcontainers -@DirtiesContext -class AvcEventProducerIntegrationSpec extends MessagingBaseSpec { - - @SpringBean - AvcEventMapper avcEventMapper = Mappers.getMapper(AvcEventMapper.class) - - @SpringBean - AvcEventProducer avcEventProducer = new AvcEventProducer(kafkaTemplate, avcEventMapper) - - @SpringBean - AvcEventConsumer acvEventConsumer = new AvcEventConsumer(avcEventProducer) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group')) - - def 'Consume and forward valid message'() { - given: 'consumer has a subscription on a topic' - def cmEventsTopic = 'cm-events' - avcEventProducer.cmEventsTopic = cmEventsTopic - kafkaConsumer.subscribe([cmEventsTopic] as List) - and: 'an event is sent' - def jsonData = TestUtils.getResourceFileContent('sampleAvcInputEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, AvcEvent.class) - when: 'the event is consumed' - acvEventConsumer.consumeAndForward(testEventSent) - and: 'the topic is polled' - def records = kafkaConsumer.poll(Duration.ofMillis(1500)) - then: 'poll returns one record' - assert records.size() == 1 - and: 'record can be converted to AVC event' - def record = records.iterator().next() - def convertedAvcEvent = jsonObjectMapper.convertJsonString(record.value(), AvcEvent) - and: 'consumed forwarded NCMP event id differs from DMI event id' - assert testEventSent.eventId != convertedAvcEvent.getEventId() - and: 'correlation id matches' - assert testEventSent.eventCorrelationId == convertedAvcEvent.getEventCorrelationId() - and: 'timestamps match' - assert testEventSent.eventTime == convertedAvcEvent.getEventTime() - and: 'target matches' - assert testEventSent.eventSource == convertedAvcEvent.getEventSource() - } - -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionCreateProducerDemo.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionCreateProducerDemo.groovy deleted file mode 100644 index 0b13cfd8e..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionCreateProducerDemo.groovy +++ /dev/null @@ -1,57 +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.notifications.avc - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.event.model.SubscriptionEvent -import org.onap.cps.ncmp.utils.KafkaDemoProducerConfig -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.kafka.core.KafkaTemplate -import org.springframework.test.annotation.DirtiesContext -import spock.lang.Specification - -@SpringBootTest(classes = [KafkaDemoProducerConfig, ObjectMapper, JsonObjectMapper]) -@DirtiesContext -class SubscriptionCreateProducerDemo extends Specification { - - @Value('${app.ncmp.avc.subscription-topic}') - String subscriptionTopic; - - @Autowired - KafkaTemplate kafkaTemplate - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'produce subscription creation data event for testing'() { - given: 'avc subscription creation event data' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) - and: 'test event is sent' - kafkaTemplate.send(subscriptionTopic, "request-Id-98765", testEventSent); - and: 'print json data to console' - println(jsonData); - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionEventMapperSpec.groovy deleted file mode 100644 index 93346303a..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/SubscriptionEventMapperSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.notifications.avc - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.event.avc.SubscriptionEventMapper -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus -import org.onap.cps.ncmp.event.model.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: 'client 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 - } - -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy index 3deab112a..382d5da4e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ package org.onap.cps.ncmp.api.inventory.sync import com.hazelcast.config.Config import com.hazelcast.instance.impl.HazelcastInstanceFactory import com.hazelcast.map.IMap -import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler +import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState -- cgit 1.2.3-korg