From df31bcf92002b2b7cba9b1187e68995c2af53cf0 Mon Sep 17 00:00:00 2001 From: ToineSiebelink Date: Thu, 27 Jun 2024 15:35:37 +0100 Subject: move lcm/common events classes -moved api.impl.events.lcm to impl.inventory.sync.lcm -moved most api.impl.events class to utils.events (remaining classes in api.impl.events belong to cmsubscrption and Priyank wil take care of those) Issue-ID: CPS-2258 Change-Id: I1818194e708aa0d9c713b470e878997c2f26fb13 Signed-off-by: ToineSiebelink --- .../ncmp/api/impl/NcmpDatastoreRequestHandler.java | 2 +- .../NcmpPassthroughResourceRequestHandler.java | 2 +- .../onap/cps/ncmp/api/impl/events/NcmpEvent.java | 66 ------ .../events/avc/ncmptoclient/AvcEventPublisher.java | 82 ------- ...otificationSubscriptionDmiOutEventConsumer.java | 4 +- ...otificationSubscriptionNcmpInEventConsumer.java | 4 +- .../api/impl/events/lcm/LcmEventHeaderMapper.java | 36 --- .../cps/ncmp/api/impl/events/lcm/LcmEventType.java | 38 ---- .../events/lcm/LcmEventsCmHandleStateHandler.java | 55 ----- .../LcmEventsCmHandleStateHandlerAsyncHelper.java | 79 ------- .../lcm/LcmEventsCmHandleStateHandlerImpl.java | 208 ------------------ .../ncmp/api/impl/events/lcm/LcmEventsCreator.java | 131 ----------- .../impl/events/lcm/LcmEventsCreatorHelper.java | 227 ------------------- .../ncmp/api/impl/events/lcm/LcmEventsService.java | 74 ------- .../api/impl/events/mapper/CloudEventMapper.java | 61 ------ .../data/operation/DataOperationEventCreator.java | 2 +- .../inventory/CmHandleRegistrationService.java | 2 +- .../ncmp/impl/inventory/sync/ModuleSyncTasks.java | 2 +- .../inventory/sync/lcm/LcmEventHeaderMapper.java | 36 +++ .../ncmp/impl/inventory/sync/lcm/LcmEventType.java | 38 ++++ .../sync/lcm/LcmEventsCmHandleStateHandler.java | 55 +++++ .../LcmEventsCmHandleStateHandlerAsyncHelper.java | 79 +++++++ .../lcm/LcmEventsCmHandleStateHandlerImpl.java | 208 ++++++++++++++++++ .../impl/inventory/sync/lcm/LcmEventsCreator.java | 131 +++++++++++ .../inventory/sync/lcm/LcmEventsCreatorHelper.java | 227 +++++++++++++++++++ .../impl/inventory/sync/lcm/LcmEventsService.java | 74 +++++++ .../DeviceTrustLevelMessageConsumer.java | 2 +- .../inventory/trustlevel/TrustLevelManager.java | 8 +- .../org/onap/cps/ncmp/utils/TopicValidator.java | 47 ---- .../cps/ncmp/utils/events/CloudEventMapper.java | 61 ++++++ .../cps/ncmp/utils/events/CmAvcEventPublisher.java | 81 +++++++ .../org/onap/cps/ncmp/utils/events/NcmpEvent.java | 66 ++++++ .../onap/cps/ncmp/utils/events/TopicValidator.java | 47 ++++ .../async/DataOperationEventConsumerSpec.groovy | 7 +- .../impl/events/avc/AvcEventConsumerSpec.groovy | 5 +- .../avc/ncmptoclient/AvcEventPublisherSpec.groovy | 63 ------ ...cationSubscriptionDmiInEventProducerSpec.groovy | 2 +- ...tionSubscriptionNcmpOutEventProducerSpec.groovy | 2 +- ...NotificationSubscriptionCacheHandlerSpec.groovy | 2 +- .../LcmEventsCmHandleStateHandlerImplSpec.groovy | 242 --------------------- .../impl/events/lcm/LcmEventsCreatorSpec.groovy | 193 ---------------- .../impl/events/lcm/LcmEventsPublisherSpec.groovy | 104 --------- .../impl/events/lcm/LcmEventsServiceSpec.groovy | 81 ------- .../impl/operations/DmiDataOperationsSpec.groovy | 2 +- .../ResourceDataOperationRequestUtilsSpec.groovy | 2 +- .../CmHandleRegistrationServiceSpec.groovy | 2 +- .../impl/inventory/sync/ModuleSyncTasksSpec.groovy | 2 +- .../LcmEventsCmHandleStateHandlerImplSpec.groovy | 242 +++++++++++++++++++++ .../inventory/sync/lcm/LcmEventsCreatorSpec.groovy | 193 ++++++++++++++++ .../sync/lcm/LcmEventsPublisherSpec.groovy | 104 +++++++++ .../inventory/sync/lcm/LcmEventsServiceSpec.groovy | 81 +++++++ .../trustlevel/TrustLevelManagerSpec.groovy | 4 +- .../onap/cps/ncmp/utils/TopicValidatorSpec.groovy | 47 ---- .../utils/events/CmAvcEventPublisherSpec.groovy | 61 ++++++ .../ncmp/utils/events/TopicValidatorSpec.groovy | 46 ++++ 55 files changed, 1860 insertions(+), 1862 deletions(-) delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java delete 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/events/mapper/CloudEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/TopicValidator.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/TopicValidatorSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy (limited to 'cps-ncmp-service') diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandler.java index 302ba449c..95453a71d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandler.java @@ -24,7 +24,7 @@ import java.util.Map; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.models.CmResourceAddress; -import org.onap.cps.ncmp.utils.TopicValidator; +import org.onap.cps.ncmp.utils.events.TopicValidator; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpPassthroughResourceRequestHandler.java index 0fd32501c..0867ab44a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpPassthroughResourceRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpPassthroughResourceRequestHandler.java @@ -34,7 +34,7 @@ import org.onap.cps.ncmp.api.models.CmResourceAddress; import org.onap.cps.ncmp.api.models.DataOperationRequest; import org.onap.cps.ncmp.exceptions.OperationNotSupportedException; import org.onap.cps.ncmp.exceptions.PayloadTooLargeException; -import org.onap.cps.ncmp.utils.TopicValidator; +import org.onap.cps.ncmp.utils.events.TopicValidator; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java deleted file mode 100644 index 248db9805..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; -import java.net.URI; -import java.util.Map; -import java.util.UUID; -import lombok.Builder; -import org.apache.commons.lang3.StringUtils; -import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter; -import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext; -import org.onap.cps.utils.JsonObjectMapper; - -@Builder -public class NcmpEvent { - - private Object data; - private Map extensions; - private String type; - @Builder.Default - private static final String CLOUD_EVENT_SPEC_VERSION_V1 = "1.0.0"; - @Builder.Default - private static final String CLOUD_EVENT_SOURCE = "NCMP"; - - /** - * Creates ncmp cloud event with provided attributes. - * - * @return Cloud Event - */ - public CloudEvent asCloudEvent() { - final JsonObjectMapper jsonObjectMapper = CpsApplicationContext.getCpsBean(JsonObjectMapper.class); - final CloudEventBuilder cloudEventBuilder = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSource(URI.create(CLOUD_EVENT_SOURCE)) - .withType(type) - .withDataSchema(URI.create("urn:cps:" + type + ":" + CLOUD_EVENT_SPEC_VERSION_V1)) - .withTime(EventDateTimeFormatter.toIsoOffsetDateTime( - EventDateTimeFormatter.getCurrentIsoFormattedDateTime())) - .withData(jsonObjectMapper.asJsonBytes(data)); - extensions.entrySet().stream() - .filter(extensionEntry -> StringUtils.isNotBlank(extensionEntry.getValue())) - .forEach(extensionEntry -> - cloudEventBuilder.withExtension(extensionEntry.getKey(), extensionEntry.getValue())); - return cloudEventBuilder.build(); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java deleted file mode 100644 index 7afe606f4..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.ncmptoclient; - -import io.cloudevents.CloudEvent; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import org.onap.cps.events.EventsPublisher; -import org.onap.cps.ncmp.api.impl.events.NcmpEvent; -import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc; -import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent; -import org.onap.cps.ncmp.events.avc.ncmp_to_client.Data; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class AvcEventPublisher { - - private final EventsPublisher eventsPublisher; - - @Value("${app.ncmp.avc.cm-events-topic}") - private String avcTopic; - - /** - * Publish attribute value change event. - * - * @param eventKey id of the cmHandle being registered - */ - public void publishAvcEvent(final String eventKey, final String attributeName, - final String oldAttributeValue, final String newAttributeValue) { - final AvcEvent avcEvent = buildAvcEvent(attributeName, oldAttributeValue, newAttributeValue); - - final Map extensions = createAvcEventExtensions(eventKey); - final CloudEvent avcCloudEvent = - NcmpEvent.builder().type(AvcEvent.class.getTypeName()) - .data(avcEvent).extensions(extensions).build().asCloudEvent(); - - eventsPublisher.publishCloudEvent(avcTopic, eventKey, avcCloudEvent); - } - - private AvcEvent buildAvcEvent(final String attributeName, - final String oldAttributeValue, - final String newAttributeValue) { - final Avc avc = new Avc(); - avc.setAttributeName(attributeName); - avc.setOldAttributeValue(oldAttributeValue); - avc.setNewAttributeValue(newAttributeValue); - - final Data payload = new Data(); - payload.setAttributeValueChange(Collections.singletonList(avc)); - final AvcEvent avcEvent = new AvcEvent(); - avcEvent.setData(payload); - return avcEvent; - } - - private Map createAvcEventExtensions(final String eventKey) { - final Map extensions = new HashMap<>(); - extensions.put("correlationid", eventKey); - return extensions; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java index 051949c5e..978a4cdfe 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java @@ -22,7 +22,7 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_ACCEPTED; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_REJECTED; -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent; +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent; import io.cloudevents.CloudEvent; import java.util.Map; @@ -120,4 +120,4 @@ public class CmNotificationSubscriptionDmiOutEventConsumer { && ncmpResponseStatus.getMessage() .equals(cmNotificationSubscriptionDmiOutData.getStatusMessage()); } -} \ No newline at end of file +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java index fb3388c11..65f4ee8c8 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java @@ -20,7 +20,7 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer; -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent; +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent; import io.cloudevents.CloudEvent; import java.util.List; @@ -67,4 +67,4 @@ public class CmNotificationSubscriptionNcmpInEventConsumer { cmNotificationSubscriptionHandlerService.processSubscriptionDeleteRequest(subscriptionId, predicates); } } -} \ No newline at end of file +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java deleted file mode 100644 index f7707d9f7..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm; - -import org.mapstruct.Mapper; -import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; -import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; - -@Mapper(componentModel = "spring") -public interface LcmEventHeaderMapper { - - /** - * Mapper for converting incoming {@link LcmEvent} to outgoing {@link LcmEventHeader}. - */ - - LcmEventHeader toLcmEventHeader(LcmEvent lcmEvent); - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java deleted file mode 100644 index a8d00f7e3..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.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 deleted file mode 100644 index 3a4995786..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm; - -import java.util.Collection; -import java.util.Map; -import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; - -/** - * 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); - - /** - * Sets the initial state of cmHandles to ADVISED. - * - * @param yangModelCmHandles List of Yang Model Cm Handle. - */ - void initiateStateAdvised(Collection yangModelCmHandles); -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java deleted file mode 100644 index af745caa4..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm; - -import java.util.Collection; -import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; -import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; -import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; -import org.onap.cps.ncmp.impl.utils.YangDataConverter; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class LcmEventsCmHandleStateHandlerAsyncHelper { - - private final LcmEventsCreator lcmEventsCreator; - private final LcmEventsService lcmEventsService; - - /** - * Publish LCM Event in asynchronous manner. - * - * @param targetNcmpServiceCmHandle target NcmpServiceCmHandle - * @param currentNcmpServiceCmHandle current NcmpServiceCmHandle - */ - @Async("notificationExecutor") - 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 LcmEventHeader lcmEventHeader = - lcmEventsCreator.populateLcmEventHeader(cmHandleId, targetNcmpServiceCmHandle, - existingNcmpServiceCmHandle); - final LcmEvent lcmEvent = - lcmEventsCreator.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - lcmEventsService.publishLcmEvent(cmHandleId, lcmEvent, lcmEventHeader); - } - - private static NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) { - return YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle); - } -} 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 deleted file mode 100644 index 4376014f3..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm; - -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED; -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED; -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.LOCKED; -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY; - -import io.micrometer.core.annotation.Timed; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -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.inventory.models.CompositeState; -import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; -import org.onap.cps.ncmp.impl.inventory.CompositeStateUtils; -import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; -import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; -import org.onap.cps.ncmp.impl.utils.YangDataConverter; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor -public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleStateHandler { - - private final InventoryPersistence inventoryPersistence; - private final LcmEventsCmHandleStateHandlerAsyncHelper lcmEventsCmHandleStateHandlerAsyncHelper; - - @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); - lcmEventsCmHandleStateHandlerAsyncHelper.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); - lcmEventsCmHandleStateHandlerAsyncHelper.publishLcmEventBatchAsynchronously(cmHandleTransitionPairs); - } - - @Override - public void initiateStateAdvised(final Collection yangModelCmHandles) { - final Map cmHandleStatePerCmHandle = new HashMap<>(yangModelCmHandles.size()); - for (final YangModelCmHandle yangModelCmHandle : yangModelCmHandles) { - cmHandleStatePerCmHandle.put(yangModelCmHandle, ADVISED); - } - updateCmHandleStateBatch(cmHandleStatePerCmHandle); - } - - 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())) { - 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() - )) { - 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(yangModelCmHandle.getCompositeState()); - CompositeStateUtils.setCompositeState(READY, yangModelCmHandle.getCompositeState()); - } - - private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) { - CompositeStateUtils.setCompositeStateForRetry(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, yangModelCmHandle.getCompositeState()); - } - - private boolean isNew(final CompositeState existingCompositeState) { - return (existingCompositeState == null); - } - - 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.toNcmpServiceCmHandle(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 deleted file mode 100644 index 4231c9967..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm; - -import java.util.UUID; -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.EventDateTimeFormatter; -import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; -import org.onap.cps.ncmp.events.lcm.v1.Event; -import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; -import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; -import org.onap.cps.ncmp.events.lcm.v1.Values; -import org.springframework.stereotype.Component; - - -/** - * LcmEventsCreator to create LcmEvent based on relevant operation. - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class LcmEventsCreator { - - private final LcmEventHeaderMapper lcmEventHeaderMapper; - - /** - * 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); - } - - /** - * Populate Lifecycle Management Event Header. - * - * @param cmHandleId cm handle identifier - * @param targetNcmpServiceCmHandle target ncmp service cmhandle - * @param existingNcmpServiceCmHandle existing ncmp service cmhandle - * @return Populated LcmEventHeader - */ - public LcmEventHeader populateLcmEventHeader(final String cmHandleId, - final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - return createLcmEventHeader(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 LcmEventHeader createLcmEventHeader(final String cmHandleId, - final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle) { - final LcmEventType lcmEventType = - LcmEventsCreatorHelper.determineEventType(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); - final LcmEvent lcmEventWithHeaderInformation = lcmEventHeader(cmHandleId, lcmEventType); - return lcmEventHeaderMapper.toLcmEventHeader(lcmEventWithHeaderInformation); - } - - private Event lcmEventPayload(final String eventCorrelationId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, - final NcmpServiceCmHandle existingNcmpServiceCmHandle, final LcmEventType lcmEventType) { - final Event event = new Event(); - event.setCmHandleId(eventCorrelationId); - event.setAlternateId(targetNcmpServiceCmHandle.getAlternateId()); - event.setModuleSetTag(targetNcmpServiceCmHandle.getModuleSetTag()); - event.setDataProducerIdentifier(targetNcmpServiceCmHandle.getDataProducerIdentifier()); - 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.getCurrentIsoFormattedDateTime()); - 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; - } - -} 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 deleted file mode 100644 index 7c7a9722c..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/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.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.impl.inventory.models.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.inventory.models.NcmpServiceCmHandle; -import org.onap.cps.ncmp.events.lcm.v1.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 deleted file mode 100644 index f51b58c3e..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm; - -import io.micrometer.core.annotation.Timed; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.events.EventsPublisher; -import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; -import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; -import org.onap.cps.utils.JsonObjectMapper; -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; - private final JsonObjectMapper jsonObjectMapper; - - @Value("${app.lcm.events.topic:ncmp-events}") - private String topicName; - - @Value("${notification.enabled:true}") - private boolean notificationsEnabled; - - /** - * Publish the LcmEvent with header to the public topic. - * - * @param cmHandleId Cm Handle Id - * @param lcmEvent Lcm Event - * @param lcmEventHeader Lcm Event Header - */ - @Timed(value = "cps.ncmp.lcm.events.publish", description = "Time taken to publish a LCM event") - public void publishLcmEvent(final String cmHandleId, final LcmEvent lcmEvent, final LcmEventHeader lcmEventHeader) { - if (notificationsEnabled) { - try { - final Map lcmEventHeadersMap = - jsonObjectMapper.convertToValueType(lcmEventHeader, Map.class); - eventsPublisher.publishEvent(topicName, cmHandleId, lcmEventHeadersMap, 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/mapper/CloudEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java deleted file mode 100644 index 4120970e5..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.mapper; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.cloudevents.CloudEvent; -import io.cloudevents.core.CloudEventUtils; -import io.cloudevents.core.data.PojoCloudEventData; -import io.cloudevents.jackson.PojoCloudEventDataMapper; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class CloudEventMapper { - - private static final ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Generic method to map cloud event data to target event class object. - * - * @param cloudEvent input cloud event - * @param targetEventClass target event class - * @param target event class type - * @return mapped target event - */ - public static T toTargetEvent(final CloudEvent cloudEvent, final Class targetEventClass) { - PojoCloudEventData mappedCloudEvent = null; - - try { - mappedCloudEvent = - CloudEventUtils.mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, targetEventClass)); - - } catch (final RuntimeException runtimeException) { - log.error("Unable to map cloud event to target event class type : {} with cause : {}", targetEventClass, - runtimeException.getMessage()); - } - - return mappedCloudEvent == null ? null : mappedCloudEvent.getValue(); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java index 42bad89f5..68b14349d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java @@ -29,11 +29,11 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NcmpResponseStatus; -import org.onap.cps.ncmp.api.impl.events.NcmpEvent; import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation; import org.onap.cps.ncmp.events.async1_0_0.Data; import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent; import org.onap.cps.ncmp.events.async1_0_0.Response; +import org.onap.cps.ncmp.utils.events.NcmpEvent; import org.springframework.util.MultiValueMap; @Slf4j diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java index 1cbba7d6c..78feca56f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java @@ -47,7 +47,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker; import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.CompositeState; @@ -59,6 +58,7 @@ import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.ncmp.impl.inventory.sync.ModuleOperationsUtils; +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelCacheConfig; import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager; import org.onap.cps.spi.exceptions.AlreadyDefinedException; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java index 08db195ad..39ea38aaf 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java @@ -29,12 +29,12 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.impl.utils.YangDataConverter; import org.onap.cps.spi.model.DataNode; import org.springframework.stereotype.Component; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java new file mode 100644 index 000000000..739583830 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java @@ -0,0 +1,36 @@ +/* + * ============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.impl.inventory.sync.lcm; + +import org.mapstruct.Mapper; +import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; +import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; + +@Mapper(componentModel = "spring") +public interface LcmEventHeaderMapper { + + /** + * Mapper for converting incoming {@link LcmEvent} to outgoing {@link LcmEventHeader}. + */ + + LcmEventHeader toLcmEventHeader(LcmEvent lcmEvent); + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java new file mode 100644 index 000000000..4bc2f1021 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/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.impl.inventory.sync.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/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java new file mode 100644 index 000000000..6cce15326 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java @@ -0,0 +1,55 @@ +/* + * ============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.impl.inventory.sync.lcm; + +import java.util.Collection; +import java.util.Map; +import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; + +/** + * 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); + + /** + * Sets the initial state of cmHandles to ADVISED. + * + * @param yangModelCmHandles List of Yang Model Cm Handle. + */ + void initiateStateAdvised(Collection yangModelCmHandles); +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java new file mode 100644 index 000000000..cf7921c35 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java @@ -0,0 +1,79 @@ +/* + * ============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.impl.inventory.sync.lcm; + +import java.util.Collection; +import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; +import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.utils.YangDataConverter; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class LcmEventsCmHandleStateHandlerAsyncHelper { + + private final LcmEventsCreator lcmEventsCreator; + private final LcmEventsService lcmEventsService; + + /** + * Publish LCM Event in asynchronous manner. + * + * @param targetNcmpServiceCmHandle target NcmpServiceCmHandle + * @param currentNcmpServiceCmHandle current NcmpServiceCmHandle + */ + @Async("notificationExecutor") + 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 LcmEventHeader lcmEventHeader = + lcmEventsCreator.populateLcmEventHeader(cmHandleId, targetNcmpServiceCmHandle, + existingNcmpServiceCmHandle); + final LcmEvent lcmEvent = + lcmEventsCreator.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + lcmEventsService.publishLcmEvent(cmHandleId, lcmEvent, lcmEventHeader); + } + + private static NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) { + return YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java new file mode 100644 index 000000000..b1b7b955f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java @@ -0,0 +1,208 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.inventory.sync.lcm; + +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED; +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED; +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.LOCKED; +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY; + +import io.micrometer.core.annotation.Timed; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +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.inventory.models.CompositeState; +import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.impl.inventory.CompositeStateUtils; +import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; +import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.utils.YangDataConverter; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleStateHandler { + + private final InventoryPersistence inventoryPersistence; + private final LcmEventsCmHandleStateHandlerAsyncHelper lcmEventsCmHandleStateHandlerAsyncHelper; + + @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); + lcmEventsCmHandleStateHandlerAsyncHelper.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); + lcmEventsCmHandleStateHandlerAsyncHelper.publishLcmEventBatchAsynchronously(cmHandleTransitionPairs); + } + + @Override + public void initiateStateAdvised(final Collection yangModelCmHandles) { + final Map cmHandleStatePerCmHandle = new HashMap<>(yangModelCmHandles.size()); + for (final YangModelCmHandle yangModelCmHandle : yangModelCmHandles) { + cmHandleStatePerCmHandle.put(yangModelCmHandle, ADVISED); + } + updateCmHandleStateBatch(cmHandleStatePerCmHandle); + } + + 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())) { + 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() + )) { + 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(yangModelCmHandle.getCompositeState()); + CompositeStateUtils.setCompositeState(READY, yangModelCmHandle.getCompositeState()); + } + + private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) { + CompositeStateUtils.setCompositeStateForRetry(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, yangModelCmHandle.getCompositeState()); + } + + private boolean isNew(final CompositeState existingCompositeState) { + return (existingCompositeState == null); + } + + 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.toNcmpServiceCmHandle(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/impl/inventory/sync/lcm/LcmEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java new file mode 100644 index 000000000..3ce6b9159 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java @@ -0,0 +1,131 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.inventory.sync.lcm; + +import java.util.UUID; +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.EventDateTimeFormatter; +import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.events.lcm.v1.Event; +import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; +import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; +import org.onap.cps.ncmp.events.lcm.v1.Values; +import org.springframework.stereotype.Component; + + +/** + * LcmEventsCreator to create LcmEvent based on relevant operation. + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class LcmEventsCreator { + + private final LcmEventHeaderMapper lcmEventHeaderMapper; + + /** + * 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); + } + + /** + * Populate Lifecycle Management Event Header. + * + * @param cmHandleId cm handle identifier + * @param targetNcmpServiceCmHandle target ncmp service cmhandle + * @param existingNcmpServiceCmHandle existing ncmp service cmhandle + * @return Populated LcmEventHeader + */ + public LcmEventHeader populateLcmEventHeader(final String cmHandleId, + final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + return createLcmEventHeader(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 LcmEventHeader createLcmEventHeader(final String cmHandleId, + final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle) { + final LcmEventType lcmEventType = + LcmEventsCreatorHelper.determineEventType(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle); + final LcmEvent lcmEventWithHeaderInformation = lcmEventHeader(cmHandleId, lcmEventType); + return lcmEventHeaderMapper.toLcmEventHeader(lcmEventWithHeaderInformation); + } + + private Event lcmEventPayload(final String eventCorrelationId, final NcmpServiceCmHandle targetNcmpServiceCmHandle, + final NcmpServiceCmHandle existingNcmpServiceCmHandle, final LcmEventType lcmEventType) { + final Event event = new Event(); + event.setCmHandleId(eventCorrelationId); + event.setAlternateId(targetNcmpServiceCmHandle.getAlternateId()); + event.setModuleSetTag(targetNcmpServiceCmHandle.getModuleSetTag()); + event.setDataProducerIdentifier(targetNcmpServiceCmHandle.getDataProducerIdentifier()); + 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.getCurrentIsoFormattedDateTime()); + 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; + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java new file mode 100644 index 000000000..348894d1b --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/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.impl.inventory.sync.lcm; + +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED; +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.CREATE; +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.DELETE; +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.UPDATE; + +import com.google.common.collect.MapDifference; +import com.google.common.collect.Maps; +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.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.events.lcm.v1.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/impl/inventory/sync/lcm/LcmEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java new file mode 100644 index 000000000..10aebfa45 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.inventory.sync.lcm; + +import io.micrometer.core.annotation.Timed; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.events.EventsPublisher; +import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; +import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; +import org.onap.cps.utils.JsonObjectMapper; +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; + private final JsonObjectMapper jsonObjectMapper; + + @Value("${app.lcm.events.topic:ncmp-events}") + private String topicName; + + @Value("${notification.enabled:true}") + private boolean notificationsEnabled; + + /** + * Publish the LcmEvent with header to the public topic. + * + * @param cmHandleId Cm Handle Id + * @param lcmEvent Lcm Event + * @param lcmEventHeader Lcm Event Header + */ + @Timed(value = "cps.ncmp.lcm.events.publish", description = "Time taken to publish a LCM event") + public void publishLcmEvent(final String cmHandleId, final LcmEvent lcmEvent, final LcmEventHeader lcmEventHeader) { + if (notificationsEnabled) { + try { + final Map lcmEventHeadersMap = + jsonObjectMapper.convertToValueType(lcmEventHeader, Map.class); + eventsPublisher.publishEvent(topicName, cmHandleId, lcmEventHeadersMap, 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/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java index 64ae80087..617fe7f01 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java @@ -24,9 +24,9 @@ import io.cloudevents.CloudEvent; import io.cloudevents.kafka.impl.KafkaHeaders; import lombok.RequiredArgsConstructor; import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper; import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel; +import org.onap.cps.ncmp.utils.events.CloudEventMapper; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java index c7bfb1dbb..22311c6b5 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java @@ -24,11 +24,11 @@ import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @@ -44,7 +44,7 @@ public class TrustLevelManager { private final Map trustLevelPerDmiPlugin; private final InventoryPersistence inventoryPersistence; - private final AvcEventPublisher avcEventPublisher; + private final CmAvcEventPublisher cmAvcEventPublisher; private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel"; private static final String AVC_NO_OLD_VALUE = null; @@ -65,7 +65,7 @@ public class TrustLevelManager { } trustLevelPerCmHandle.put(cmHandleId, initialTrustLevel); if (TrustLevel.NONE.equals(initialTrustLevel)) { - avcEventPublisher.publishAvcEvent(cmHandleId, + cmAvcEventPublisher.publishAvcEvent(cmHandleId, AVC_CHANGED_ATTRIBUTE_NAME, AVC_NO_OLD_VALUE, initialTrustLevel.name()); @@ -126,7 +126,7 @@ public class TrustLevelManager { } else { log.info("The trust level for Cm Handle: {} is now: {} ", notificationCandidateCmHandleId, newEffectiveTrustLevel); - avcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId, + cmAvcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId, AVC_CHANGED_ATTRIBUTE_NAME, oldEffectiveTrustLevel.name(), newEffectiveTrustLevel.name()); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/TopicValidator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/TopicValidator.java deleted file mode 100644 index f9fed8d43..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/TopicValidator.java +++ /dev/null @@ -1,47 +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.utils; - -import java.util.regex.Pattern; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.onap.cps.ncmp.exceptions.InvalidTopicException; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class TopicValidator { - - private static final Pattern TOPIC_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9]([._-](?![._-])|" - + "[a-zA-Z0-9]){0,120}[a-zA-Z0-9]$"); - - /** - * Validate kafka topic name pattern. - * - * @param topicName name of the topic to be validated - * - * @throws InvalidTopicException if the topic is not valid - */ - public static void validateTopicName(final String topicName) { - if (!TOPIC_NAME_PATTERN.matcher(topicName).matches()) { - throw new InvalidTopicException("Topic name " + topicName + " is invalid", "invalid topic"); - } - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java new file mode 100644 index 000000000..4462b169e --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java @@ -0,0 +1,61 @@ +/* + * ============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.utils.events; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.cloudevents.CloudEvent; +import io.cloudevents.core.CloudEventUtils; +import io.cloudevents.core.data.PojoCloudEventData; +import io.cloudevents.jackson.PojoCloudEventDataMapper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CloudEventMapper { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * Generic method to map cloud event data to target event class object. + * + * @param cloudEvent input cloud event + * @param targetEventClass target event class + * @param target event class type + * @return mapped target event + */ + public static T toTargetEvent(final CloudEvent cloudEvent, final Class targetEventClass) { + PojoCloudEventData mappedCloudEvent = null; + + try { + mappedCloudEvent = + CloudEventUtils.mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, targetEventClass)); + + } catch (final RuntimeException runtimeException) { + log.error("Unable to map cloud event to target event class type : {} with cause : {}", targetEventClass, + runtimeException.getMessage()); + } + + return mappedCloudEvent == null ? null : mappedCloudEvent.getValue(); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java new file mode 100644 index 000000000..2a9717cc1 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.utils.events; + +import io.cloudevents.CloudEvent; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.onap.cps.events.EventsPublisher; +import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc; +import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent; +import org.onap.cps.ncmp.events.avc.ncmp_to_client.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CmAvcEventPublisher { + + private final EventsPublisher eventsPublisher; + + @Value("${app.ncmp.avc.cm-events-topic}") + private String avcTopic; + + /** + * Publish attribute value change event. + * + * @param eventKey id of the cmHandle being registered + */ + public void publishAvcEvent(final String eventKey, final String attributeName, + final String oldAttributeValue, final String newAttributeValue) { + final AvcEvent avcEvent = buildAvcEvent(attributeName, oldAttributeValue, newAttributeValue); + + final Map extensions = createAvcEventExtensions(eventKey); + final CloudEvent avcCloudEvent = + NcmpEvent.builder().type(AvcEvent.class.getTypeName()) + .data(avcEvent).extensions(extensions).build().asCloudEvent(); + + eventsPublisher.publishCloudEvent(avcTopic, eventKey, avcCloudEvent); + } + + private AvcEvent buildAvcEvent(final String attributeName, + final String oldAttributeValue, + final String newAttributeValue) { + final Avc avc = new Avc(); + avc.setAttributeName(attributeName); + avc.setOldAttributeValue(oldAttributeValue); + avc.setNewAttributeValue(newAttributeValue); + + final Data payload = new Data(); + payload.setAttributeValueChange(Collections.singletonList(avc)); + final AvcEvent avcEvent = new AvcEvent(); + avcEvent.setData(payload); + return avcEvent; + } + + private Map createAvcEventExtensions(final String eventKey) { + final Map extensions = new HashMap<>(); + extensions.put("correlationid", eventKey); + return extensions; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java new file mode 100644 index 000000000..67128bd15 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java @@ -0,0 +1,66 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.utils.events; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import java.net.URI; +import java.util.Map; +import java.util.UUID; +import lombok.Builder; +import org.apache.commons.lang3.StringUtils; +import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter; +import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext; +import org.onap.cps.utils.JsonObjectMapper; + +@Builder +public class NcmpEvent { + + private Object data; + private Map extensions; + private String type; + @Builder.Default + private static final String CLOUD_EVENT_SPEC_VERSION_V1 = "1.0.0"; + @Builder.Default + private static final String CLOUD_EVENT_SOURCE = "NCMP"; + + /** + * Creates ncmp cloud event with provided attributes. + * + * @return Cloud Event + */ + public CloudEvent asCloudEvent() { + final JsonObjectMapper jsonObjectMapper = CpsApplicationContext.getCpsBean(JsonObjectMapper.class); + final CloudEventBuilder cloudEventBuilder = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create(CLOUD_EVENT_SOURCE)) + .withType(type) + .withDataSchema(URI.create("urn:cps:" + type + ":" + CLOUD_EVENT_SPEC_VERSION_V1)) + .withTime(EventDateTimeFormatter.toIsoOffsetDateTime( + EventDateTimeFormatter.getCurrentIsoFormattedDateTime())) + .withData(jsonObjectMapper.asJsonBytes(data)); + extensions.entrySet().stream() + .filter(extensionEntry -> StringUtils.isNotBlank(extensionEntry.getValue())) + .forEach(extensionEntry -> + cloudEventBuilder.withExtension(extensionEntry.getKey(), extensionEntry.getValue())); + return cloudEventBuilder.build(); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java new file mode 100644 index 000000000..a7ad86cda --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java @@ -0,0 +1,47 @@ +/* + * ============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.utils.events; + +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.onap.cps.ncmp.exceptions.InvalidTopicException; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TopicValidator { + + private static final Pattern TOPIC_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9]([._-](?![._-])|" + + "[a-zA-Z0-9]){0,120}[a-zA-Z0-9]$"); + + /** + * Validate kafka topic name pattern. + * + * @param topicName name of the topic to be validated + * + * @throws InvalidTopicException if the topic is not valid + */ + public static void validateTopicName(final String topicName) { + if (!TOPIC_NAME_PATTERN.matcher(topicName).matches()) { + throw new InvalidTopicException("Topic name " + topicName + " is invalid", "invalid topic"); + } + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy index b095f904a..5193642b0 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy @@ -20,14 +20,12 @@ package org.onap.cps.ncmp.api.impl.async -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent - import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder import io.cloudevents.kafka.CloudEventDeserializer import io.cloudevents.kafka.CloudEventSerializer import io.cloudevents.kafka.impl.KafkaHeaders -import io.cloudevents.core.builder.CloudEventBuilder import org.apache.kafka.clients.consumer.ConsumerRecord import org.apache.kafka.clients.consumer.KafkaConsumer import org.apache.kafka.common.header.internals.RecordHeaders @@ -42,8 +40,11 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.kafka.listener.adapter.RecordFilterStrategy import org.springframework.test.annotation.DirtiesContext import org.testcontainers.spock.Testcontainers + import java.time.Duration +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent + @SpringBootTest(classes = [EventsPublisher, DataOperationEventConsumer, RecordFilterStrategies, JsonObjectMapper, ObjectMapper]) @Testcontainers @DirtiesContext diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy index a90fd9405..0f5d4fe5a 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy @@ -37,9 +37,10 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.annotation.DirtiesContext import org.testcontainers.spock.Testcontainers + import java.time.Duration -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent @SpringBootTest(classes = [EventsPublisher, AvcEventConsumer, ObjectMapper, JsonObjectMapper]) @Testcontainers @@ -91,4 +92,4 @@ class AvcEventConsumerSpec extends MessagingBaseSpec { assert testEventSent == convertedAvcEvent } -} \ No newline at end of file +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy deleted file mode 100644 index 101a29b29..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2023-2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.ncmptoclient - -import com.fasterxml.jackson.databind.ObjectMapper -import io.cloudevents.CloudEvent -import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc -import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.test.context.ContextConfiguration - -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent - -@ContextConfiguration(classes = [CpsApplicationContext, ObjectMapper, JsonObjectMapper]) -class AvcEventPublisherSpec extends MessagingBaseSpec { - - def mockEventsPublisher = Mock(EventsPublisher) - def objectUnderTest = new AvcEventPublisher(mockEventsPublisher) - - def 'Publish an attribute value change event'() { - given: 'the event key' - def someEventKey = 'someEventKey' - and: 'the name of the attribute being changed' - def someAttributeName = 'someAttributeName' - and: 'the old value of the attribute' - def someOldAttributeValue = 'someOldAttributeValue' - and: 'the new value of the attribute' - def someNewAttributeValue = 'someNewAttributeValue' - when: 'an attribute value change event is published' - objectUnderTest.publishAvcEvent(someEventKey, someAttributeName, someOldAttributeValue, someNewAttributeValue) - then: 'the cloud event publisher is invoked with the correct data' - 1 * mockEventsPublisher.publishCloudEvent(_, someEventKey, - cloudEvent -> { - def actualAvcs = toTargetEvent(cloudEvent, AvcEvent.class).data.attributeValueChange - def expectedAvc = new Avc(attributeName: someAttributeName, - oldAttributeValue: someOldAttributeValue, - newAttributeValue: someNewAttributeValue) - assert actualAvcs == [expectedAvc] - }) - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy index 039a18949..253763b13 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy @@ -24,10 +24,10 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import org.onap.cps.events.EventsPublisher import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionDmiInEventProducer -import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmHandle import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Data +import org.onap.cps.ncmp.utils.events.CloudEventMapper import org.onap.cps.utils.JsonObjectMapper import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy index 77bbe7ebc..1fb5837eb 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy @@ -4,9 +4,9 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import org.onap.cps.events.EventsPublisher import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionNcmpOutEventProducer -import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.Data +import org.onap.cps.ncmp.utils.events.CloudEventMapper import org.onap.cps.utils.JsonObjectMapper import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy index 393432fc5..7d4bd73aa 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy @@ -37,7 +37,7 @@ import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent @SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { 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 deleted file mode 100644 index 1adf01c55..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy +++ /dev/null @@ -1,242 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm - -import org.onap.cps.ncmp.api.inventory.models.CompositeState -import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState -import org.onap.cps.ncmp.impl.inventory.InventoryPersistence -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle -import spock.lang.Specification - -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETING -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.LOCKED -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY -import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED - -class LcmEventsCmHandleStateHandlerImplSpec extends Specification { - - def mockInventoryPersistence = Mock(InventoryPersistence) - def mockLcmEventsCreator = Mock(LcmEventsCreator) - def mockLcmEventsService = Mock(LcmEventsService) - - def lcmEventsCmHandleStateHandlerAsyncHelper = new LcmEventsCmHandleStateHandlerAsyncHelper(mockLcmEventsCreator, mockLcmEventsService) - def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, lcmEventsCmHandleStateHandlerAsyncHelper) - - 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 - 'DELETED to ADVISED' | DELETED | ADVISED || 0 | 1 - } - - 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(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 from DELETING to ADVISED'() { - given: 'Cm Handle represented as YangModelCmHandle in DELETING state' - yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) - when: 'update state is invoked' - objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) - then: 'the cm handle 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 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 yangModelCmHandlesToBeCreated = setupBatch('NEW') - when: 'instantiating a batch of new cm handles' - objectUnderTest.initiateStateAdvised(yangModelCmHandlesToBeCreated) - 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 events' - 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 events' - 2 * mockLcmEventsService.publishLcmEvent(_, _, _) - } - - def 'Batch of existing cm handles is deleted'() { - given: 'A batch of deleted cm handles' - def cmHandleStateMap = setupBatch('DELETED') - 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).isEmpty() - } - } - and: 'event service is called to publish events' - 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, yangModelCmHandle2] - } - - if ('DELETED' == type) { - yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: READY) - yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY) - return [(yangModelCmHandle1): DELETED, (yangModelCmHandle2): DELETED] - } - - 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] - } - } -} 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 deleted file mode 100644 index 36024b74e..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy +++ /dev/null @@ -1,193 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm - -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.inventory.models.CompositeState -import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle -import org.onap.cps.ncmp.events.lcm.v1.Values -import org.onap.cps.ncmp.impl.inventory.models.CmHandleState -import spock.lang.Specification - -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETING -import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY - -class LcmEventsCreatorSpec extends Specification { - - LcmEventHeaderMapper lcmEventsHeaderMapper = Mappers.getMapper(LcmEventHeaderMapper) - - def objectUnderTest = new LcmEventsCreator(lcmEventsHeaderMapper) - 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 - - } - - def 'Map the LcmEventHeader'() { - given: 'NCMP cm handle details with current and old details' - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(cmHandleState: ADVISED)) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(cmHandleState: READY)) - when: 'the event header is populated' - def result = objectUnderTest.populateLcmEventHeader(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) - then: 'the header has fields populated' - assert result.eventCorrelationId == cmHandleId - assert result.eventId != null - } - - def 'Map the LcmEvent for alternate ID, data producer identifier, and module set tag when they contain #scenario'() { - given: 'NCMP cm handle details with current and old values for alternate ID, module set tag, and data producer identifier' - def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: existingAlternateId, moduleSetTag: existingModuleSetTag, dataProducerIdentifier: existingDataProducerIdentifier, compositeState: new CompositeState(dataSyncEnabled: false)) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: targetAlternateId, moduleSetTag: targetModuleSetTag, dataProducerIdentifier: targetDataProducerIdentifier, compositeState: new CompositeState(dataSyncEnabled: false)) - when: 'the event is populated' - def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) - then: 'the alternate ID, module set tag, and data producer identifier are present or are an empty string in the payload' - assert result.event.alternateId == targetAlternateId - assert result.event.moduleSetTag == targetModuleSetTag - assert result.event.dataProducerIdentifier == targetDataProducerIdentifier - where: 'the following values are provided for the alternate ID, module set tag, and data producer identifier' - scenario | existingAlternateId | targetAlternateId | existingModuleSetTag | targetModuleSetTag | existingDataProducerIdentifier | targetDataProducerIdentifier - 'same target and existing values' | 'someAlternateId' | 'someAlternateId' | 'someModuleSetTag' | 'someModuleSetTag' | 'someDataProducerIdentifier' | 'someDataProducerIdentifier' - 'blank target and existing values' | '' | '' | '' | '' | '' | '' - 'new target value and blank existing values' | '' | 'someAlternateId' | '' | 'someAlternateId' | '' | 'someDataProducerIdentifier' - } -} 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 deleted file mode 100644 index e2bdc5d1f..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy +++ /dev/null @@ -1,104 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm - -import com.fasterxml.jackson.databind.ObjectMapper -import org.apache.kafka.clients.consumer.KafkaConsumer -import org.apache.kafka.common.serialization.StringDeserializer -import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.lcm.v1.Event -import org.onap.cps.ncmp.events.lcm.v1.LcmEvent -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.springframework.util.SerializationUtils -import org.testcontainers.spock.Testcontainers - -import java.time.Duration - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -@Testcontainers -@DirtiesContext -class LcmEventsPublisherSpec extends MessagingBaseSpec { - - def legacyEventKafkaConsumer = new KafkaConsumer<>(eventConsumerConfigProperties('ncmp-group', StringDeserializer)) - - def testTopic = 'ncmp-events-test' - - @SpringBean - EventsPublisher lcmEventsPublisher = new EventsPublisher(legacyEventKafkaTemplate, cloudEventKafkaTemplate) - - @Autowired - JsonObjectMapper jsonObjectMapper - - - def 'Produce and Consume Lcm Event'() { - given: 'event key and event data' - def eventKey = 'lcm' - def eventId = 'test-uuid' - def eventCorrelationId = 'cmhandle-test' - def eventSource = 'org.onap.ncmp' - def eventTime = '2022-12-31T20:30:40.000+0000' - def eventType = 'org.onap.ncmp.cmhandle.lcm.event' - def eventSchema = 'org.onap.ncmp.cmhandle.lcm.event' - def eventSchemaVersion = 'v1' - def eventData = new LcmEvent( - eventId: eventId, - eventCorrelationId: eventCorrelationId, - eventSource: eventSource, - eventTime: eventTime, - eventType: eventType, - eventSchema: eventSchema, - eventSchemaVersion: eventSchemaVersion, - event: new Event(cmHandleId: 'cmhandle-test')) - and: 'we have a event header' - def eventHeader = [ - eventId : eventId, - eventCorrelationId: eventCorrelationId, - eventSource : eventSource, - eventTime : eventTime, - eventType : eventType, - eventSchema : eventSchema, - eventSchemaVersion: eventSchemaVersion] - and: 'consumer has a subscription' - legacyEventKafkaConsumer.subscribe([testTopic] as List) - when: 'an event is published' - lcmEventsPublisher.publishEvent(testTopic, eventKey, eventHeader, eventData) - and: 'topic is polled' - def records = legacyEventKafkaConsumer.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) - and: 'record header matches the expected parameters' - assert SerializationUtils.deserialize(record.headers().lastHeader('eventId').value()) == eventId - assert SerializationUtils.deserialize(record.headers().lastHeader('eventCorrelationId').value()) == eventCorrelationId - } -} 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 deleted file mode 100644 index 0b6b5a7b9..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.lcm - -import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.events.lcm.v1.LcmEvent -import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.kafka.KafkaException -import spock.lang.Specification - -class LcmEventsServiceSpec extends Specification { - - def mockLcmEventsPublisher = Mock(EventsPublisher) - def mockJsonObjectMapper = Mock(JsonObjectMapper) - - def objectUnderTest = new LcmEventsService(mockLcmEventsPublisher, mockJsonObjectMapper) - - def 'Create and Publish lcm event where events are #scenario'() { - given: 'a cm handle id, Lcm Event, and headers' - def cmHandleId = 'test-cm-handle-id' - def eventId = UUID.randomUUID().toString() - def lcmEvent = new LcmEvent(eventId: eventId, eventCorrelationId: cmHandleId) - and: 'we also have a lcm event header' - def lcmEventHeader = new LcmEventHeader(eventId: eventId, eventCorrelationId: cmHandleId) - and: 'notificationsEnabled is #notificationsEnabled and it will be true as default' - objectUnderTest.notificationsEnabled = notificationsEnabled - and: 'lcm event header is transformed to headers map' - mockJsonObjectMapper.convertToValueType(lcmEventHeader, Map.class) >> ['eventId': eventId, 'eventCorrelationId': cmHandleId] - when: 'service is called to publish lcm event' - objectUnderTest.publishLcmEvent('test-cm-handle-id', lcmEvent, lcmEventHeader) - then: 'publisher is called #expectedTimesMethodCalled times' - expectedTimesMethodCalled * mockLcmEventsPublisher.publishEvent(_, cmHandleId, _, lcmEvent) >> { - args -> { - def eventHeaders = (args[2] as Map) - assert eventHeaders.containsKey('eventId') - assert eventHeaders.containsKey('eventCorrelationId') - assert eventHeaders.get('eventId') == eventId - assert eventHeaders.get('eventCorrelationId') == cmHandleId - } - } - 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 eventId = UUID.randomUUID().toString() - def lcmEvent = new LcmEvent(eventId: eventId, eventCorrelationId: cmHandleId) - def lcmEventHeader = new LcmEventHeader(eventId: eventId, 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, lcmEventHeader) - 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/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy index 1e877f4a8..5799f53ec 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy @@ -42,13 +42,13 @@ import reactor.core.publisher.Mono import spock.lang.Shared import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent @SpringBootTest @ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, DmiProperties, DmiDataOperations]) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy index d8d04d44a..2ed18089c 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy @@ -42,9 +42,9 @@ import org.springframework.util.LinkedMultiValueMap import java.time.Duration -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent @ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext]) class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy index 9d4d9565e..5ab678959 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy @@ -24,7 +24,6 @@ package org.onap.cps.ncmp.impl.inventory import com.hazelcast.map.IMap import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.impl.exception.DmiRequestException import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse @@ -35,6 +34,7 @@ import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.api.inventory.models.UpgradedCmHandles import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.CpsException diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy index a9dbf07e2..ee49f2f90 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy @@ -28,13 +28,13 @@ import ch.qos.logback.core.read.ListAppender import com.hazelcast.config.Config import com.hazelcast.instance.impl.HazelcastInstanceFactory import com.hazelcast.map.IMap -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.spi.model.DataNode import org.slf4j.LoggerFactory import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy new file mode 100644 index 000000000..bd7c321bc --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy @@ -0,0 +1,242 @@ +/* + * ============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.impl.inventory.sync.lcm + +import org.onap.cps.ncmp.api.inventory.models.CompositeState +import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState +import org.onap.cps.ncmp.impl.inventory.InventoryPersistence +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import spock.lang.Specification + +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETING +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.LOCKED +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY +import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED + +class LcmEventsCmHandleStateHandlerImplSpec extends Specification { + + def mockInventoryPersistence = Mock(InventoryPersistence) + def mockLcmEventsCreator = Mock(LcmEventsCreator) + def mockLcmEventsService = Mock(LcmEventsService) + + def lcmEventsCmHandleStateHandlerAsyncHelper = new LcmEventsCmHandleStateHandlerAsyncHelper(mockLcmEventsCreator, mockLcmEventsService) + def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, lcmEventsCmHandleStateHandlerAsyncHelper) + + 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 + 'DELETED to ADVISED' | DELETED | ADVISED || 0 | 1 + } + + 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(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 from DELETING to ADVISED'() { + given: 'Cm Handle represented as YangModelCmHandle in DELETING state' + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + when: 'update state is invoked' + objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) + then: 'the cm handle 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 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 yangModelCmHandlesToBeCreated = setupBatch('NEW') + when: 'instantiating a batch of new cm handles' + objectUnderTest.initiateStateAdvised(yangModelCmHandlesToBeCreated) + 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 events' + 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 events' + 2 * mockLcmEventsService.publishLcmEvent(_, _, _) + } + + def 'Batch of existing cm handles is deleted'() { + given: 'A batch of deleted cm handles' + def cmHandleStateMap = setupBatch('DELETED') + 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).isEmpty() + } + } + and: 'event service is called to publish events' + 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, yangModelCmHandle2] + } + + if ('DELETED' == type) { + yangModelCmHandle1.compositeState = new CompositeState(cmHandleState: READY) + yangModelCmHandle2.compositeState = new CompositeState(cmHandleState: READY) + return [(yangModelCmHandle1): DELETED, (yangModelCmHandle2): DELETED] + } + + 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] + } + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy new file mode 100644 index 000000000..e0a552ea9 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy @@ -0,0 +1,193 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.inventory.sync.lcm + +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.inventory.models.CompositeState +import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.events.lcm.v1.Values +import org.onap.cps.ncmp.impl.inventory.models.CmHandleState +import spock.lang.Specification + +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETING +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY + +class LcmEventsCreatorSpec extends Specification { + + LcmEventHeaderMapper lcmEventsHeaderMapper = Mappers.getMapper(LcmEventHeaderMapper) + + def objectUnderTest = new LcmEventsCreator(lcmEventsHeaderMapper) + 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 + + } + + def 'Map the LcmEventHeader'() { + given: 'NCMP cm handle details with current and old details' + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(cmHandleState: ADVISED)) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(cmHandleState: READY)) + when: 'the event header is populated' + def result = objectUnderTest.populateLcmEventHeader(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) + then: 'the header has fields populated' + assert result.eventCorrelationId == cmHandleId + assert result.eventId != null + } + + def 'Map the LcmEvent for alternate ID, data producer identifier, and module set tag when they contain #scenario'() { + given: 'NCMP cm handle details with current and old values for alternate ID, module set tag, and data producer identifier' + def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: existingAlternateId, moduleSetTag: existingModuleSetTag, dataProducerIdentifier: existingDataProducerIdentifier, compositeState: new CompositeState(dataSyncEnabled: false)) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: targetAlternateId, moduleSetTag: targetModuleSetTag, dataProducerIdentifier: targetDataProducerIdentifier, compositeState: new CompositeState(dataSyncEnabled: false)) + when: 'the event is populated' + def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle) + then: 'the alternate ID, module set tag, and data producer identifier are present or are an empty string in the payload' + assert result.event.alternateId == targetAlternateId + assert result.event.moduleSetTag == targetModuleSetTag + assert result.event.dataProducerIdentifier == targetDataProducerIdentifier + where: 'the following values are provided for the alternate ID, module set tag, and data producer identifier' + scenario | existingAlternateId | targetAlternateId | existingModuleSetTag | targetModuleSetTag | existingDataProducerIdentifier | targetDataProducerIdentifier + 'same target and existing values' | 'someAlternateId' | 'someAlternateId' | 'someModuleSetTag' | 'someModuleSetTag' | 'someDataProducerIdentifier' | 'someDataProducerIdentifier' + 'blank target and existing values' | '' | '' | '' | '' | '' | '' + 'new target value and blank existing values' | '' | 'someAlternateId' | '' | 'someAlternateId' | '' | 'someDataProducerIdentifier' + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy new file mode 100644 index 000000000..e7674761c --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy @@ -0,0 +1,104 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.inventory.sync.lcm + +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.kafka.clients.consumer.KafkaConsumer +import org.apache.kafka.common.serialization.StringDeserializer +import org.onap.cps.events.EventsPublisher +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.lcm.v1.Event +import org.onap.cps.ncmp.events.lcm.v1.LcmEvent +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.springframework.util.SerializationUtils +import org.testcontainers.spock.Testcontainers + +import java.time.Duration + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +@Testcontainers +@DirtiesContext +class LcmEventsPublisherSpec extends MessagingBaseSpec { + + def legacyEventKafkaConsumer = new KafkaConsumer<>(eventConsumerConfigProperties('ncmp-group', StringDeserializer)) + + def testTopic = 'ncmp-events-test' + + @SpringBean + EventsPublisher lcmEventsPublisher = new EventsPublisher(legacyEventKafkaTemplate, cloudEventKafkaTemplate) + + @Autowired + JsonObjectMapper jsonObjectMapper + + + def 'Produce and Consume Lcm Event'() { + given: 'event key and event data' + def eventKey = 'lcm' + def eventId = 'test-uuid' + def eventCorrelationId = 'cmhandle-test' + def eventSource = 'org.onap.ncmp' + def eventTime = '2022-12-31T20:30:40.000+0000' + def eventType = 'org.onap.ncmp.cmhandle.lcm.event' + def eventSchema = 'org.onap.ncmp.cmhandle.lcm.event' + def eventSchemaVersion = 'v1' + def eventData = new LcmEvent( + eventId: eventId, + eventCorrelationId: eventCorrelationId, + eventSource: eventSource, + eventTime: eventTime, + eventType: eventType, + eventSchema: eventSchema, + eventSchemaVersion: eventSchemaVersion, + event: new Event(cmHandleId: 'cmhandle-test')) + and: 'we have a event header' + def eventHeader = [ + eventId : eventId, + eventCorrelationId: eventCorrelationId, + eventSource : eventSource, + eventTime : eventTime, + eventType : eventType, + eventSchema : eventSchema, + eventSchemaVersion: eventSchemaVersion] + and: 'consumer has a subscription' + legacyEventKafkaConsumer.subscribe([testTopic] as List) + when: 'an event is published' + lcmEventsPublisher.publishEvent(testTopic, eventKey, eventHeader, eventData) + and: 'topic is polled' + def records = legacyEventKafkaConsumer.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) + and: 'record header matches the expected parameters' + assert SerializationUtils.deserialize(record.headers().lastHeader('eventId').value()) == eventId + assert SerializationUtils.deserialize(record.headers().lastHeader('eventCorrelationId').value()) == eventCorrelationId + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy new file mode 100644 index 000000000..b745734f0 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.inventory.sync.lcm + +import org.onap.cps.events.EventsPublisher +import org.onap.cps.ncmp.events.lcm.v1.LcmEvent +import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.kafka.KafkaException +import spock.lang.Specification + +class LcmEventsServiceSpec extends Specification { + + def mockLcmEventsPublisher = Mock(EventsPublisher) + def mockJsonObjectMapper = Mock(JsonObjectMapper) + + def objectUnderTest = new LcmEventsService(mockLcmEventsPublisher, mockJsonObjectMapper) + + def 'Create and Publish lcm event where events are #scenario'() { + given: 'a cm handle id, Lcm Event, and headers' + def cmHandleId = 'test-cm-handle-id' + def eventId = UUID.randomUUID().toString() + def lcmEvent = new LcmEvent(eventId: eventId, eventCorrelationId: cmHandleId) + and: 'we also have a lcm event header' + def lcmEventHeader = new LcmEventHeader(eventId: eventId, eventCorrelationId: cmHandleId) + and: 'notificationsEnabled is #notificationsEnabled and it will be true as default' + objectUnderTest.notificationsEnabled = notificationsEnabled + and: 'lcm event header is transformed to headers map' + mockJsonObjectMapper.convertToValueType(lcmEventHeader, Map.class) >> ['eventId': eventId, 'eventCorrelationId': cmHandleId] + when: 'service is called to publish lcm event' + objectUnderTest.publishLcmEvent('test-cm-handle-id', lcmEvent, lcmEventHeader) + then: 'publisher is called #expectedTimesMethodCalled times' + expectedTimesMethodCalled * mockLcmEventsPublisher.publishEvent(_, cmHandleId, _, lcmEvent) >> { + args -> { + def eventHeaders = (args[2] as Map) + assert eventHeaders.containsKey('eventId') + assert eventHeaders.containsKey('eventCorrelationId') + assert eventHeaders.get('eventId') == eventId + assert eventHeaders.get('eventCorrelationId') == cmHandleId + } + } + 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 eventId = UUID.randomUUID().toString() + def lcmEvent = new LcmEvent(eventId: eventId, eventCorrelationId: cmHandleId) + def lcmEventHeader = new LcmEventHeader(eventId: eventId, 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, lcmEventHeader) + then: 'the exception is just logged and not bubbled up' + noExceptionThrown() + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy index 4c22dbaed..b5bfbc165 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy @@ -20,10 +20,10 @@ package org.onap.cps.ncmp.impl.inventory.trustlevel -import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher import spock.lang.Specification class TrustLevelManagerSpec extends Specification { @@ -32,7 +32,7 @@ class TrustLevelManagerSpec extends Specification { def trustLevelPerDmiPlugin = [:] def mockInventoryPersistence = Mock(InventoryPersistence) - def mockAttributeValueChangeEventPublisher = Mock(AvcEventPublisher) + def mockAttributeValueChangeEventPublisher = Mock(CmAvcEventPublisher) def objectUnderTest = new TrustLevelManager(trustLevelPerCmHandle, trustLevelPerDmiPlugin, mockInventoryPersistence, mockAttributeValueChangeEventPublisher) def 'Initial cm handle registration'() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/TopicValidatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/TopicValidatorSpec.groovy deleted file mode 100644 index f96502984..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/TopicValidatorSpec.groovy +++ /dev/null @@ -1,47 +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.utils - -import org.onap.cps.ncmp.exceptions.InvalidTopicException -import org.onap.cps.ncmp.utils.TopicValidator -import spock.lang.Specification - -class TopicValidatorSpec extends Specification { - - def 'Valid topic name validation.'() { - when: 'a valid topic name is validated' - TopicValidator.validateTopicName('my-valid-topic') - then: 'no exception is thrown' - noExceptionThrown() - } - - def 'Validating invalid topic names.'() { - when: 'the invalid topic name is validated' - TopicValidator.validateTopicName(topicName) - then: 'boolean response will be returned for #scenario' - thrown(InvalidTopicException) - where: 'the following names are used' - scenario | topicName - 'empty topic' | '' - 'blank topic' | ' ' - 'invalid non empty topic' | '1_5_*_#' - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy new file mode 100644 index 000000000..247f32183 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy @@ -0,0 +1,61 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023-2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.utils.events + +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.CloudEvent +import org.onap.cps.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc +import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.test.context.ContextConfiguration + +@ContextConfiguration(classes = [CpsApplicationContext, ObjectMapper, JsonObjectMapper]) +class CmAvcEventPublisherSpec extends MessagingBaseSpec { + + def mockEventsPublisher = Mock(EventsPublisher) + def objectUnderTest = new CmAvcEventPublisher(mockEventsPublisher) + + def 'Publish an attribute value change event'() { + given: 'the event key' + def someEventKey = 'someEventKey' + and: 'the name of the attribute being changed' + def someAttributeName = 'someAttributeName' + and: 'the old value of the attribute' + def someOldAttributeValue = 'someOldAttributeValue' + and: 'the new value of the attribute' + def someNewAttributeValue = 'someNewAttributeValue' + when: 'an attribute value change event is published' + objectUnderTest.publishAvcEvent(someEventKey, someAttributeName, someOldAttributeValue, someNewAttributeValue) + then: 'the cloud event publisher is invoked with the correct data' + 1 * mockEventsPublisher.publishCloudEvent(_, someEventKey, + cloudEvent -> { + def actualAvcs = CloudEventMapper.toTargetEvent(cloudEvent, AvcEvent.class).data.attributeValueChange + def expectedAvc = new Avc(attributeName: someAttributeName, + oldAttributeValue: someOldAttributeValue, + newAttributeValue: someNewAttributeValue) + assert actualAvcs == [expectedAvc] + }) + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy new file mode 100644 index 000000000..26148f870 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy @@ -0,0 +1,46 @@ +/* + * ============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.utils.events + +import org.onap.cps.ncmp.exceptions.InvalidTopicException +import spock.lang.Specification + +class TopicValidatorSpec extends Specification { + + def 'Valid topic name validation.'() { + when: 'a valid topic name is validated' + TopicValidator.validateTopicName('my-valid-topic') + then: 'no exception is thrown' + noExceptionThrown() + } + + def 'Validating invalid topic names.'() { + when: 'the invalid topic name is validated' + TopicValidator.validateTopicName(topicName) + then: 'boolean response will be returned for #scenario' + thrown(InvalidTopicException) + where: 'the following names are used' + scenario | topicName + 'empty topic' | '' + 'blank topic' | ' ' + 'invalid non empty topic' | '1_5_*_#' + } +} -- cgit 1.2.3-korg