From 183a22c664b4cd11072901ea3854c56e9256facc Mon Sep 17 00:00:00 2001 From: emaclee Date: Wed, 13 Dec 2023 00:41:31 +0000 Subject: Moving and Renaming eexisting subscription impl -renamed the existing subscription related packages to have 'deprecated' on its name as this shall be removed with new implementation of the subscription positive cases - replaced the existing schemas with the new ones Issue-ID: CPS-1991 Signed-off-by: emaclee Change-Id: I8f27861b80756540477e03971c53219ea589975c --- .../subscriptions/SubscriptionPersistence.java | 50 +++++ .../subscriptions/SubscriptionPersistenceImpl.java | 199 ++++++++++++++++++++ .../subscriptions/SubscriptionStatus.java | 49 +++++ .../CmSubscriptionDmiOutEventConsumer.java | 104 ---------- ...OutEventToYangModelSubscriptionEventMapper.java | 55 ------ ...ionEventToCmSubscriptionNcmpOutEventMapper.java | 105 ----------- .../CmSubscriptionNcmpInEventConsumer.java | 96 ---------- .../CmSubscriptionNcmpInEventForwarder.java | 204 -------------------- .../CmSubscriptionNcmpInEventMapper.java | 52 ----- ...cmpInEventToCmSubscriptionDmiInEventMapper.java | 35 ---- .../CmSubscriptionNcmpOutEventPublisher.java | 146 -------------- .../events/cmsubscription/ResponseTimeoutTask.java | 52 ----- .../CmSubscriptionDmiOutEventConsumer.java | 104 ++++++++++ ...OutEventToYangModelSubscriptionEventMapper.java | 56 ++++++ ...ionEventToCmSubscriptionNcmpOutEventMapper.java | 105 +++++++++++ .../CmSubscriptionNcmpInEventConsumer.java | 96 ++++++++++ .../CmSubscriptionNcmpInEventForwarder.java | 204 ++++++++++++++++++++ .../CmSubscriptionNcmpInEventMapper.java | 52 +++++ ...cmpInEventToCmSubscriptionDmiInEventMapper.java | 35 ++++ .../CmSubscriptionNcmpOutEventPublisher.java | 146 ++++++++++++++ .../cmsubscription/ResponseTimeoutTask.java | 52 +++++ .../subscriptions/SubscriptionPersistence.java | 50 ----- .../subscriptions/SubscriptionPersistenceImpl.java | 199 -------------------- .../api/impl/subscriptions/SubscriptionStatus.java | 49 ----- .../yangmodels/YangModelSubscriptionEvent.java | 2 +- .../cps/ncmp/api/models/CmSubscriptionStatus.java | 2 +- .../ncmp/api/models/SubscriptionEventResponse.java | 2 +- .../SubscriptionPersistenceSpec.groovy | 99 ++++++++++ ...lientCmSubscriptionNcmpInEventMapperSpec.groovy | 60 ------ .../CmSubscriptionDmiOutEventConsumerSpec.groovy | 140 -------------- ...ntToYangModelSubscriptionEventMapperSpec.groovy | 60 ------ ...ntToCmSubscriptionNcmpOutEventMapperSpec.groovy | 89 --------- .../CmSubscriptionNcmpInEventConsumerSpec.groovy | 106 ----------- .../CmSubscriptionNcmpInEventForwarderSpec.groovy | 209 --------------------- .../CmSubscriptionNcmpInEventMapperSpec.groovy | 78 -------- .../CmSubscriptionNcmpOutEventPublisherSpec.groovy | 128 ------------- ...lientCmSubscriptionNcmpInEventMapperSpec.groovy | 60 ++++++ .../CmSubscriptionDmiOutEventConsumerSpec.groovy | 140 ++++++++++++++ ...ntToYangModelSubscriptionEventMapperSpec.groovy | 60 ++++++ ...ntToCmSubscriptionNcmpOutEventMapperSpec.groovy | 89 +++++++++ .../CmSubscriptionNcmpInEventConsumerSpec.groovy | 106 +++++++++++ .../CmSubscriptionNcmpInEventForwarderSpec.groovy | 209 +++++++++++++++++++++ .../CmSubscriptionNcmpInEventMapperSpec.groovy | 78 ++++++++ .../CmSubscriptionNcmpOutEventPublisherSpec.groovy | 128 +++++++++++++ .../SubscriptionPersistenceSpec.groovy | 99 ---------- 45 files changed, 2120 insertions(+), 2119 deletions(-) create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistence.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceImpl.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionStatus.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarder.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ResponseTimeoutTask.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistence.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceImpl.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionStatus.java create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceSpec.groovy (limited to 'cps-ncmp-service') diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistence.java new file mode 100644 index 000000000..7aa073d35 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistence.java @@ -0,0 +1,50 @@ +/* + * ============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.deprecated.subscriptions; + +import java.util.Collection; +import org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.spi.model.DataNode; + +public interface SubscriptionPersistence extends NcmpPersistence { + + /** + * Save subscription Event. + * + * @param yangModelSubscriptionEvent subscription Event as Yang Model. + */ + void saveSubscriptionEvent(YangModelSubscriptionEvent yangModelSubscriptionEvent); + + /** + * Get data nodes. + * + * @return the DataNode as collection. + */ + Collection getDataNodesForSubscriptionEvent(); + + /** + * Get data nodes by xpath. + * + * @return the DataNode as collection. + */ + Collection getCmHandlesForSubscriptionEvent(String clientId, String subscriptionName); +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceImpl.java new file mode 100644 index 000000000..29b7c7d04 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceImpl.java @@ -0,0 +1,199 @@ +/* + * ============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.deprecated.subscriptions; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.api.CpsDataService; +import org.onap.cps.api.CpsModuleService; +import org.onap.cps.ncmp.api.impl.inventory.NcmpPersistenceImpl; +import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.spi.FetchDescendantsOption; +import org.onap.cps.spi.model.DataNode; +import org.onap.cps.spi.utils.CpsValidator; +import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class SubscriptionPersistenceImpl extends NcmpPersistenceImpl implements SubscriptionPersistence { + + private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions"; + private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry"; + + public SubscriptionPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService, + final CpsModuleService cpsModuleService, final CpsValidator cpsValidator) { + super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator); + } + + + @Override + public void saveSubscriptionEvent(final YangModelSubscriptionEvent yangModelSubscriptionEvent) { + final String clientId = yangModelSubscriptionEvent.getClientId(); + final String subscriptionName = yangModelSubscriptionEvent.getSubscriptionName(); + + final Collection dataNodes = cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, + SUBSCRIPTION_ANCHOR_NAME, SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); + + if (isSubscriptionRegistryEmptyOrNonExist(dataNodes, clientId, subscriptionName)) { + saveSubscriptionEventYangModel(createSubscriptionEventJsonData( + jsonObjectMapper.asJsonString(yangModelSubscriptionEvent))); + } else { + findDeltaCmHandlesAddOrUpdateInDatabase(yangModelSubscriptionEvent, clientId, subscriptionName, dataNodes); + } + } + + private void findDeltaCmHandlesAddOrUpdateInDatabase(final YangModelSubscriptionEvent yangModelSubscriptionEvent, + final String clientId, final String subscriptionName, + final Collection dataNodes) { + final Map> cmHandleIdToStatusAndDetailsAsMapNew = + extractCmHandleFromYangModelAsMap(yangModelSubscriptionEvent); + final Map> cmHandleIdToStatusAndDetailsAsMapOriginal = + DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode(dataNodes); + + final Map> newTargetCmHandles = mapDifference(cmHandleIdToStatusAndDetailsAsMapNew, + cmHandleIdToStatusAndDetailsAsMapOriginal); + traverseCmHandleList(newTargetCmHandles, clientId, subscriptionName, true); + + final Map> existingTargetCmHandles = + mapDifference(cmHandleIdToStatusAndDetailsAsMapNew, newTargetCmHandles); + traverseCmHandleList(existingTargetCmHandles, clientId, subscriptionName, false); + } + + private static Map> extractCmHandleFromYangModelAsMap( + final YangModelSubscriptionEvent yangModelSubscriptionEvent) { + return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles() + .stream().collect( + HashMap::new, + (result, cmHandle) -> { + final String cmHandleId = cmHandle.getCmHandleId(); + final SubscriptionStatus status = cmHandle.getStatus(); + final String details = cmHandle.getDetails(); + + if (cmHandleId != null && status != null) { + result.put(cmHandleId, new HashMap<>()); + result.get(cmHandleId).put("status", status.toString()); + result.get(cmHandleId).put("details", details == null ? "" : details); + } + }, + HashMap::putAll + ); + } + + private void traverseCmHandleList(final Map> cmHandleMap, + final String clientId, + final String subscriptionName, + final boolean isAddListElementOperation) { + final List cmHandleList = targetCmHandlesAsList(cmHandleMap); + for (final YangModelSubscriptionEvent.TargetCmHandle targetCmHandle : cmHandleList) { + final String targetCmHandleAsJson = + createTargetCmHandleJsonData(jsonObjectMapper.asJsonString(targetCmHandle)); + addOrReplaceCmHandlePredicateListElement(targetCmHandleAsJson, clientId, subscriptionName, + isAddListElementOperation); + } + } + + private boolean isSubscriptionRegistryEmptyOrNonExist(final Collection dataNodes, + final String clientId, final String subscriptionName) { + final Optional dataNodeFirst = dataNodes.stream().findFirst(); + return ((dataNodeFirst.isPresent() && dataNodeFirst.get().getChildDataNodes().isEmpty()) + || getCmHandlesForSubscriptionEvent(clientId, subscriptionName).isEmpty()); + } + + private void addOrReplaceCmHandlePredicateListElement(final String targetCmHandleAsJson, + final String clientId, + final String subscriptionName, + final boolean isAddListElementOperation) { + if (isAddListElementOperation) { + log.info("targetCmHandleAsJson to be added into DB {}", targetCmHandleAsJson); + cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP); + } else { + log.info("targetCmHandleAsJson to be updated into DB {}", targetCmHandleAsJson); + cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP); + } + } + + private void saveSubscriptionEventYangModel(final String subscriptionEventJsonData) { + log.info("SubscriptionEventJsonData to be saved into DB {}", subscriptionEventJsonData); + cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + SUBSCRIPTION_REGISTRY_PARENT, subscriptionEventJsonData, NO_TIMESTAMP); + } + + @Override + public Collection getDataNodesForSubscriptionEvent() { + return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); + } + + @Override + public Collection getCmHandlesForSubscriptionEvent(final String clientId, final String subscriptionName) { + return cpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + List.of(createCmHandleXpath(clientId, subscriptionName)), + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); + } + + private static List targetCmHandlesAsList( + final Map> newCmHandles) { + return newCmHandles.entrySet().stream().map(entry -> { + final String cmHandleId = entry.getKey(); + final Map statusAndDetailsMap = entry.getValue(); + final String status = statusAndDetailsMap.get("status"); + final String details = statusAndDetailsMap.get("details"); + return new YangModelSubscriptionEvent.TargetCmHandle(cmHandleId, SubscriptionStatus.fromString(status), + details); + }).collect(Collectors.toList()); + } + + private static String createSubscriptionEventJsonData(final String yangModelSubscriptionAsJson) { + return "{\"subscription\":[" + yangModelSubscriptionAsJson + "]}"; + } + + private static String createTargetCmHandleJsonData(final String targetCmHandleAsJson) { + return "{\"targetCmHandles\":[" + targetCmHandleAsJson + "]}"; + } + + private static String createCmHandleXpathPredicates(final String clientId, final String subscriptionName) { + return "/subscription-registry/subscription[@clientID='" + clientId + + "' and @subscriptionName='" + subscriptionName + "']/predicates"; + } + + private static String createCmHandleXpath(final String clientId, final String subscriptionName) { + return "/subscription-registry/subscription[@clientID='" + clientId + + "' and @subscriptionName='" + subscriptionName + "']"; + } + + private static Map> mapDifference(final Map> left, + final Map> right) { + final Map> difference = new HashMap<>(); + difference.putAll(left); + difference.putAll(right); + difference.entrySet().removeAll(right.entrySet()); + return difference; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionStatus.java new file mode 100644 index 000000000..023e8de52 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionStatus.java @@ -0,0 +1,49 @@ +/* + * ============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.deprecated.subscriptions; + + +public enum SubscriptionStatus { + ACCEPTED("ACCEPTED"), + REJECTED("REJECTED"), + PENDING("PENDING"); + + private final String subscriptionStatusValue; + + SubscriptionStatus(final String subscriptionStatusValue) { + this.subscriptionStatusValue = subscriptionStatusValue; + } + + /** + * Finds the value of the given enum. + * + * @param statusValue value of the enum + * @return a SubscriptionStatus + */ + public static SubscriptionStatus fromString(final String statusValue) { + for (final SubscriptionStatus subscriptionStatusType : SubscriptionStatus.values()) { + if (subscriptionStatusType.subscriptionStatusValue.equalsIgnoreCase(statusValue)) { + return subscriptionStatusType; + } + } + return null; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java deleted file mode 100644 index d2b596ec0..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java +++ /dev/null @@ -1,104 +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.cmsubscription; - -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent; - -import com.hazelcast.map.IMap; -import io.cloudevents.CloudEvent; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@RequiredArgsConstructor -public class CmSubscriptionDmiOutEventConsumer { - - private final IMap> forwardedSubscriptionEventCache; - private final SubscriptionPersistence subscriptionPersistence; - private final CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper - cmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper; - private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; - - @Value("${notification.enabled:true}") - private boolean notificationFeatureEnabled; - - @Value("${ncmp.model-loader.subscription:false}") - private boolean subscriptionModelLoaderEnabled; - - /** - * Consume subscription response event. - * - * @param cmSubscriptionDmiOutConsumerRecord the event to be consumed - */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", - containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void consumeDmiOutEvent( - final ConsumerRecord cmSubscriptionDmiOutConsumerRecord) { - final CloudEvent cloudEvent = cmSubscriptionDmiOutConsumerRecord.value(); - final String eventType = cmSubscriptionDmiOutConsumerRecord.value().getType(); - final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent = - toTargetEvent(cloudEvent, CmSubscriptionDmiOutEvent.class); - final String clientId = cmSubscriptionDmiOutEvent.getData().getClientId(); - log.info("subscription event response of clientId: {} is received.", clientId); - final String subscriptionName = cmSubscriptionDmiOutEvent.getData().getSubscriptionName(); - final String subscriptionEventId = clientId + subscriptionName; - boolean createOutcomeResponse = true; - if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { - final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); - dmiNames.remove(cmSubscriptionDmiOutEvent.getData().getDmiName()); - forwardedSubscriptionEventCache.put(subscriptionEventId, dmiNames, - ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); - createOutcomeResponse = forwardedSubscriptionEventCache.get(subscriptionEventId).isEmpty(); - } - if (subscriptionModelLoaderEnabled) { - updateSubscriptionEvent(cmSubscriptionDmiOutEvent); - } - if (createOutcomeResponse - && notificationFeatureEnabled) { - - final CmSubscriptionEvent cmSubscriptionEvent = new CmSubscriptionEvent(); - cmSubscriptionEvent.setClientId(cmSubscriptionDmiOutEvent.getData().getClientId()); - cmSubscriptionEvent.setSubscriptionName(cmSubscriptionDmiOutEvent.getData().getSubscriptionName()); - - cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent, eventType); - forwardedSubscriptionEventCache.remove(subscriptionEventId); - } - } - - private void updateSubscriptionEvent(final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent) { - final YangModelSubscriptionEvent yangModelSubscriptionEvent = - cmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper - .toYangModelSubscriptionEvent(cmSubscriptionDmiOutEvent); - subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java deleted file mode 100644 index 77eebe36f..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.cmsubscription; - -import java.util.List; -import java.util.stream.Collectors; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus; - -@Mapper(componentModel = "spring") -public interface CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper { - - @Mapping(source = "data.clientId", target = "clientId") - @Mapping(source = "data.subscriptionName", target = "subscriptionName") - @Mapping(source = "data.subscriptionStatus", target = "predicates.targetCmHandles", - qualifiedByName = "mapSubscriptionStatusToCmHandleTargets") - YangModelSubscriptionEvent toYangModelSubscriptionEvent( - CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent); - - /** - * Maps SubscriptionStatus to list of TargetCmHandle. - * - * @param subscriptionStatus as a list - * @return TargetCmHandle list - */ - @Named("mapSubscriptionStatusToCmHandleTargets") - default List mapSubscriptionStatusToCmHandleTargets( - List subscriptionStatus) { - return subscriptionStatus.stream().map(status -> new YangModelSubscriptionEvent.TargetCmHandle(status.getId(), - org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.fromString(status.getStatus().value()), - status.getDetails())).collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java deleted file mode 100644 index 0fe2c9ae5..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.cmsubscription; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; -import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; -import org.onap.cps.ncmp.api.models.CmSubscriptionStatus; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfo; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfoDetail; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent; -import org.onap.cps.spi.exceptions.DataValidationException; - -@Mapper(componentModel = "spring") -public interface CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper { - - @Mapping(source = "cmSubscriptionStatus", target = "data.additionalInfo", - qualifiedByName = "mapCmSubscriptionStatusToAdditionalInfo") - CmSubscriptionNcmpOutEvent toCmSubscriptionNcmpOutEvent(CmSubscriptionEvent cmSubscriptionEvent); - - /** - * Maps list of SubscriptionStatus to an AdditionalInfo. - * - * @param cmSubscriptionStatusList containing details - * @return an AdditionalInfo - */ - @Named("mapCmSubscriptionStatusToAdditionalInfo") - default AdditionalInfo mapCmSubscriptionStatusToAdditionalInfo( - final List cmSubscriptionStatusList) { - if (cmSubscriptionStatusList == null || cmSubscriptionStatusList.isEmpty()) { - throw new DataValidationException("Invalid cmSubscriptionStatusList", - "CmSubscriptionStatus list cannot be null or empty"); - } - - final Map> rejectedSubscriptionsPerDetails = - getSubscriptionsPerDetails(cmSubscriptionStatusList, SubscriptionStatus.REJECTED); - final Map> rejectedCmHandlesPerDetails = - getCmHandlesPerDetails(rejectedSubscriptionsPerDetails); - final List rejectedCmHandles = getAdditionalInfoDetailList(rejectedCmHandlesPerDetails); - - final Map> pendingSubscriptionsPerDetails = - getSubscriptionsPerDetails(cmSubscriptionStatusList, SubscriptionStatus.PENDING); - final Map> pendingCmHandlesPerDetails = - getCmHandlesPerDetails(pendingSubscriptionsPerDetails); - final List pendingCmHandles = getAdditionalInfoDetailList(pendingCmHandlesPerDetails); - - final AdditionalInfo additionalInfo = new AdditionalInfo(); - additionalInfo.setRejected(rejectedCmHandles); - additionalInfo.setPending(pendingCmHandles); - - return additionalInfo; - } - - private static Map> getSubscriptionsPerDetails( - final List cmSubscriptionStatusList, final SubscriptionStatus status) { - return cmSubscriptionStatusList.stream() - .filter(subscriptionStatus -> subscriptionStatus.getStatus() == status) - .collect(Collectors.groupingBy(CmSubscriptionStatus::getDetails)); - } - - private static Map> getCmHandlesPerDetails( - final Map> cmSubscriptionsPerDetails) { - return cmSubscriptionsPerDetails.entrySet().stream() - .collect(Collectors.toMap( - Map.Entry::getKey, - entry -> entry.getValue().stream() - .map(CmSubscriptionStatus::getId) - .collect(Collectors.toList()) - )); - } - - private static List getAdditionalInfoDetailList( - final Map> cmHandlesPerDetails) { - return cmHandlesPerDetails.entrySet().stream() - .map(entry -> { - final AdditionalInfoDetail detail = new AdditionalInfoDetail(); - detail.setDetails(entry.getKey()); - detail.setTargets(entry.getValue()); - return detail; - }).collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java deleted file mode 100644 index f1c64c788..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumer.java +++ /dev/null @@ -1,96 +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.cmsubscription; - -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 io.cloudevents.CloudEvent; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - - -@Component -@Slf4j -@RequiredArgsConstructor -public class CmSubscriptionNcmpInEventConsumer { - - private final CmSubscriptionNcmpInEventForwarder cmSubscriptionNcmpInEventForwarder; - private final CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper; - private final SubscriptionPersistence subscriptionPersistence; - - @Value("${notification.enabled:true}") - private boolean notificationFeatureEnabled; - - @Value("${ncmp.model-loader.subscription:false}") - private boolean subscriptionModelLoaderEnabled; - - /** - * Consume the specified event. - * - * @param subscriptionEventConsumerRecord the event to be consumed - */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-topic}", - containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void consumeSubscriptionEvent(final ConsumerRecord subscriptionEventConsumerRecord) { - final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value(); - final String eventType = subscriptionEventConsumerRecord.value().getType(); - final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent = - toTargetEvent(cloudEvent, CmSubscriptionNcmpInEvent.class); - final String eventDatastore = cmSubscriptionNcmpInEvent.getData().getPredicates().getDatastore(); - if (!eventDatastore.equals(PASSTHROUGH_RUNNING.getDatastoreName()) || eventDatastore.equals( - PASSTHROUGH_OPERATIONAL.getDatastoreName())) { - throw new UnsupportedOperationException( - "passthrough datastores are currently only supported for event subscriptions"); - } - if ("CM".equals(cmSubscriptionNcmpInEvent.getData().getDataType().getDataCategory())) { - if (subscriptionModelLoaderEnabled) { - persistSubscriptionEvent(cmSubscriptionNcmpInEvent); - } - if ("subscriptionCreated".equals(cloudEvent.getType())) { - log.info("Subscription for ClientID {} with name {} ...", - cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID(), - cmSubscriptionNcmpInEvent.getData().getSubscription().getName()); - if (notificationFeatureEnabled) { - cmSubscriptionNcmpInEventForwarder.forwardCreateSubscriptionEvent(cmSubscriptionNcmpInEvent, - eventType); - } - } - } else { - log.trace("Non-CM subscription event ignored"); - } - } - - private void persistSubscriptionEvent(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent) { - final YangModelSubscriptionEvent yangModelSubscriptionEvent = - cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(cmSubscriptionNcmpInEvent); - subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java deleted file mode 100644 index e8086b117..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java +++ /dev/null @@ -1,204 +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.cmsubscription; - -import com.hazelcast.map.IMap; -import io.cloudevents.CloudEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; -import org.onap.cps.ncmp.api.impl.events.EventsPublisher; -import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; -import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper; -import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - - -@Component -@Slf4j -@RequiredArgsConstructor -public class CmSubscriptionNcmpInEventForwarder { - - private static final Pattern REGEX_TO_EXTRACT_DOMAIN_FROM_URL_EXCLUDING_PORT = - Pattern.compile("http[s]?:\\/\\/(?:www\\.)?([^\\/:]+):{0,1}[0-9]{0,5}"); - - private final InventoryPersistence inventoryPersistence; - private final EventsPublisher eventsPublisher; - private final IMap> forwardedSubscriptionEventCache; - private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; - private final CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper; - private final CmSubscriptionEventCloudMapper cmSubscriptionEventCloudMapper; - private final CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper - cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper; - private final SubscriptionPersistence subscriptionPersistence; - private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); - @Value("${app.ncmp.avc.subscription-forward-topic-prefix}") - private String dmiAvcSubscriptionTopicPrefix; - - @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms:30000}") - private int dmiResponseTimeoutInMs; - - /** - * Forward subscription event. - * - * @param cmSubscriptionNcmpInEvent the event to be forwarded - */ - public void forwardCreateSubscriptionEvent(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, - final String eventType) { - final List cmHandleTargets = cmSubscriptionNcmpInEvent.getData().getPredicates().getTargets(); - if (cmHandleTargets == null || cmHandleTargets.isEmpty() || cmHandleTargets.stream() - .anyMatch(id -> (id).contains("*"))) { - throw new UnsupportedOperationException( - "CMHandle targets are required. \"Wildcard\" operations are not yet supported"); - } - final Collection yangModelCmHandles = - inventoryPersistence.getYangModelCmHandles(cmHandleTargets); - final Map>> dmiPropertiesPerCmHandleIdPerServiceName = - DmiServiceNameOrganizer.getDmiPropertiesPerCmHandleIdPerServiceName(yangModelCmHandles); - findDmisAndRespond(cmSubscriptionNcmpInEvent, eventType, cmHandleTargets, - dmiPropertiesPerCmHandleIdPerServiceName); - } - - private void findDmisAndRespond(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, final String eventType, - final List cmHandleTargetsAsStrings, - final Map>> dmiPropertiesPerCmHandleIdPerServiceName) { - - final CmSubscriptionEvent cmSubscriptionEvent = new CmSubscriptionEvent(); - cmSubscriptionEvent.setSubscriptionName(cmSubscriptionNcmpInEvent.getData().getSubscription().getName()); - cmSubscriptionEvent.setClientId(cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID()); - - final List cmHandlesThatExistsInDb = - dmiPropertiesPerCmHandleIdPerServiceName.entrySet().stream().map(Map.Entry::getValue).map(Map::keySet) - .flatMap(Set::stream).collect(Collectors.toList()); - - final List targetCmHandlesDoesNotExistInDb = new ArrayList<>(cmHandleTargetsAsStrings); - targetCmHandlesDoesNotExistInDb.removeAll(cmHandlesThatExistsInDb); - - final Set dmisToRespond = new HashSet<>(dmiPropertiesPerCmHandleIdPerServiceName.keySet()); - - if (dmisToRespond.isEmpty() || !targetCmHandlesDoesNotExistInDb.isEmpty()) { - updatesCmHandlesToRejectedAndPersistSubscriptionEvent(cmSubscriptionNcmpInEvent, - targetCmHandlesDoesNotExistInDb); - } - if (dmisToRespond.isEmpty()) { - cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent, - "subscriptionCreatedStatus"); - } else { - startResponseTimeout(cmSubscriptionEvent, dmisToRespond); - final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent = - cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.toCmSubscriptionDmiInEvent( - cmSubscriptionNcmpInEvent); - forwardEventToDmis(dmiPropertiesPerCmHandleIdPerServiceName, cmSubscriptionDmiInEvent, eventType); - } - } - - private void startResponseTimeout(final CmSubscriptionEvent cmSubscriptionEvent, - final Set dmisToRespond) { - final String subscriptionClientId = cmSubscriptionEvent.getClientId(); - final String subscriptionName = cmSubscriptionEvent.getSubscriptionName(); - final String subscriptionEventId = subscriptionClientId + subscriptionName; - - forwardedSubscriptionEventCache.put(subscriptionEventId, dmisToRespond, - ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); - final ResponseTimeoutTask responseTimeoutTask = - new ResponseTimeoutTask(forwardedSubscriptionEventCache, cmSubscriptionNcmpOutEventPublisher, - cmSubscriptionEvent); - - executorService.schedule(responseTimeoutTask, dmiResponseTimeoutInMs, TimeUnit.MILLISECONDS); - } - - private void forwardEventToDmis(final Map>> dmiNameCmHandleMap, - final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent, final String eventType) { - dmiNameCmHandleMap.forEach((dmiName, cmHandlePropertiesMap) -> { - final List cmHandleTargets = cmHandlePropertiesMap.entrySet().stream().map( - cmHandleAndProperties -> { - final CmHandle cmHandle = new CmHandle(); - cmHandle.setId(cmHandleAndProperties.getKey()); - cmHandle.setAdditionalProperties(cmHandleAndProperties.getValue()); - return cmHandle; - }).collect(Collectors.toList()); - - cmSubscriptionDmiInEvent.getData().getPredicates().setTargets(cmHandleTargets); - final String dmiNameSuffix = toValidTopicSuffix(dmiName); - final String eventKey = createEventKey(cmSubscriptionDmiInEvent, dmiNameSuffix); - final String dmiAvcSubscriptionTopic = dmiAvcSubscriptionTopicPrefix + dmiNameSuffix; - - final CloudEvent cmSubscriptionDmiInCloudEvent = - cmSubscriptionEventCloudMapper.toCloudEvent(cmSubscriptionDmiInEvent, eventKey, eventType); - eventsPublisher.publishCloudEvent(dmiAvcSubscriptionTopic, eventKey, cmSubscriptionDmiInCloudEvent); - }); - } - - private String createEventKey(final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent, final String dmiName) { - return cmSubscriptionDmiInEvent.getData().getSubscription().getClientID() + "-" - + cmSubscriptionDmiInEvent.getData().getSubscription().getName() + "-" + dmiName; - } - - private void updatesCmHandlesToRejectedAndPersistSubscriptionEvent( - final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, - final List targetCmHandlesDoesNotExistInDb) { - final YangModelSubscriptionEvent yangModelSubscriptionEvent = - cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(cmSubscriptionNcmpInEvent); - yangModelSubscriptionEvent.getPredicates() - .setTargetCmHandles(findRejectedCmHandles(targetCmHandlesDoesNotExistInDb, yangModelSubscriptionEvent)); - subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); - } - - private static List findRejectedCmHandles( - final List targetCmHandlesDoesNotExistInDb, - final YangModelSubscriptionEvent yangModelSubscriptionEvent) { - return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles().stream() - .filter(targetCmHandle -> targetCmHandlesDoesNotExistInDb.contains(targetCmHandle.getCmHandleId())) - .map(target -> new YangModelSubscriptionEvent.TargetCmHandle(target.getCmHandleId(), - SubscriptionStatus.REJECTED, "Targets not found")) - .collect(Collectors.toList()); - } - - /* - CPS-1979 : DmiName can be a URL , which is not a valid topic name. - Hence just taking the domain name(excluding port) information to be part of the topic name. - */ - private String toValidTopicSuffix(final String dmiName) { - final Matcher matcher = REGEX_TO_EXTRACT_DOMAIN_FROM_URL_EXCLUDING_PORT.matcher(dmiName); - return matcher.find() ? matcher.group(1) : dmiName; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java deleted file mode 100644 index ab93f13a2..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapper.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.cmsubscription; - -import java.util.List; -import java.util.stream.Collectors; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; - -@Mapper(componentModel = "spring") -public interface CmSubscriptionNcmpInEventMapper { - - @Mapping(source = "data.subscription.clientID", target = "clientId") - @Mapping(source = "data.subscription.name", target = "subscriptionName") - @Mapping(source = "data.predicates.targets", target = "predicates.targetCmHandles", - qualifiedByName = "mapTargetsToCmHandleTargets") - @Mapping(source = "data.predicates.datastore", target = "predicates.datastore") - YangModelSubscriptionEvent toYangModelSubscriptionEvent(CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent); - - /** - * Maps list of Targets to list of TargetCmHandle. - * - * @param targets list of objects - * @return TargetCmHandle list - */ - @Named("mapTargetsToCmHandleTargets") - default List mapTargetsToCmHandleTargets(List targets) { - return targets.stream().map(YangModelSubscriptionEvent.TargetCmHandle::new) - .collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java deleted file mode 100644 index f1c166453..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java +++ /dev/null @@ -1,35 +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.cmsubscription; - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; - -@Mapper(componentModel = "spring") -public interface CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper { - - @Mapping(target = "data.predicates.targets", ignore = true) - CmSubscriptionDmiInEvent toCmSubscriptionDmiInEvent( - CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent); - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java deleted file mode 100644 index a0fd81c12..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java +++ /dev/null @@ -1,146 +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.cmsubscription; - -import static org.onap.cps.ncmp.api.NcmpResponseStatus.PARTIALLY_APPLIED_SUBSCRIPTION; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_NOT_APPLICABLE; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_PENDING; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESSFULLY_APPLIED_SUBSCRIPTION; -import static org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.ACCEPTED; -import static org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.PENDING; -import static org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.REJECTED; - -import io.cloudevents.CloudEvent; -import java.util.List; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.NcmpResponseStatus; -import org.onap.cps.ncmp.api.impl.events.EventsPublisher; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; -import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; -import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper; -import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; -import org.onap.cps.ncmp.api.models.CmSubscriptionStatus; -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@RequiredArgsConstructor -public class CmSubscriptionNcmpOutEventPublisher { - - private final SubscriptionPersistence subscriptionPersistence; - - private final EventsPublisher outcomeEventsPublisher; - - private final CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper - cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper; - - private final SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper; - - @Value("${app.ncmp.avc.subscription-outcome-topic:subscription-response}") - private String subscriptionOutcomeEventTopic; - - /** - * This is for construction of outcome message to be published for client apps. - * - * @param cmSubscriptionEvent event produced by Dmi Plugin - */ - public void sendResponse(final CmSubscriptionEvent cmSubscriptionEvent, final String eventType) { - final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent = - formCmSubscriptionNcmpOutEvent(cmSubscriptionEvent); - final String subscriptionClientId = cmSubscriptionEvent.getClientId(); - final String subscriptionName = cmSubscriptionEvent.getSubscriptionName(); - final String subscriptionEventId = subscriptionClientId + subscriptionName; - final CloudEvent subscriptionOutcomeCloudEvent = - subscriptionOutcomeCloudMapper.toCloudEvent(cmSubscriptionNcmpOutEvent, - subscriptionEventId, eventType); - outcomeEventsPublisher.publishCloudEvent(subscriptionOutcomeEventTopic, - subscriptionEventId, subscriptionOutcomeCloudEvent); - } - - private CmSubscriptionNcmpOutEvent formCmSubscriptionNcmpOutEvent( - final CmSubscriptionEvent cmSubscriptionEvent) { - final Map> cmHandleIdToStatusAndDetailsAsMap = - DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode( - subscriptionPersistence.getCmHandlesForSubscriptionEvent( - cmSubscriptionEvent.getClientId(), - cmSubscriptionEvent.getSubscriptionName())); - final List cmSubscriptionStatusList = - mapCmHandleIdStatusDetailsMapToSubscriptionStatusList(cmHandleIdToStatusAndDetailsAsMap); - cmSubscriptionEvent.setCmSubscriptionStatus(cmSubscriptionStatusList); - return fromCmSubscriptionEvent(cmSubscriptionEvent, - decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap)); - } - - private static List mapCmHandleIdStatusDetailsMapToSubscriptionStatusList( - final Map> cmHandleIdToStatusAndDetailsAsMap) { - return cmHandleIdToStatusAndDetailsAsMap.entrySet() - .stream().map(entryset -> { - final CmSubscriptionStatus cmSubscriptionStatus = new CmSubscriptionStatus(); - final String cmHandleId = entryset.getKey(); - final Map statusAndDetailsMap = entryset.getValue(); - final String status = statusAndDetailsMap.get("status"); - final String details = statusAndDetailsMap.get("details"); - cmSubscriptionStatus.setId(cmHandleId); - cmSubscriptionStatus.setStatus(SubscriptionStatus.fromString(status)); - cmSubscriptionStatus.setDetails(details); - return cmSubscriptionStatus; - }).toList(); - } - - private NcmpResponseStatus decideOnNcmpEventResponseCodeForSubscription( - final Map> cmHandleIdToStatusAndDetailsAsMap) { - - if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, ACCEPTED)) { - return SUCCESSFULLY_APPLIED_SUBSCRIPTION; - } - if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, REJECTED)) { - return SUBSCRIPTION_NOT_APPLICABLE; - } - if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, PENDING)) { - return SUBSCRIPTION_PENDING; - } - return PARTIALLY_APPLIED_SUBSCRIPTION; - } - - private boolean allTargetsHaveStatus(final Map> cmHandleIdToStatusAndDetailsAsMap, - final SubscriptionStatus subscriptionStatus) { - return cmHandleIdToStatusAndDetailsAsMap.values().stream() - .allMatch(entryset -> entryset.containsValue(subscriptionStatus.toString())); - } - - private CmSubscriptionNcmpOutEvent fromCmSubscriptionEvent( - final CmSubscriptionEvent cmSubscriptionEvent, - final NcmpResponseStatus ncmpResponseStatus) { - - final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent = - cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.toCmSubscriptionNcmpOutEvent( - cmSubscriptionEvent); - cmSubscriptionNcmpOutEvent.getData().setStatusCode(Integer.parseInt(ncmpResponseStatus.getCode())); - cmSubscriptionNcmpOutEvent.getData().setStatusMessage(ncmpResponseStatus.getMessage()); - - return cmSubscriptionNcmpOutEvent; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java deleted file mode 100644 index 78b000dae..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.cmsubscription; - -import com.hazelcast.map.IMap; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; - -@Slf4j -@RequiredArgsConstructor -public class ResponseTimeoutTask implements Runnable { - - private final IMap> forwardedSubscriptionEventCache; - private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; - private final CmSubscriptionEvent cmSubscriptionEvent; - - @Override - public void run() { - generateTimeoutResponse(); - } - - private void generateTimeoutResponse() { - final String subscriptionClientId = cmSubscriptionEvent.getClientId(); - final String subscriptionName = cmSubscriptionEvent.getSubscriptionName(); - final String subscriptionEventId = subscriptionClientId + subscriptionName; - if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { - cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent, - "subscriptionCreatedStatus"); - forwardedSubscriptionEventCache.remove(subscriptionEventId); - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumer.java new file mode 100644 index 000000000..307940c19 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumer.java @@ -0,0 +1,104 @@ +/* + * ============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.deprecated.cmsubscription; + +import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent; + +import com.hazelcast.map.IMap; +import io.cloudevents.CloudEvent; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionDmiOutEventConsumer { + + private final IMap> forwardedSubscriptionEventCache; + private final SubscriptionPersistence subscriptionPersistence; + private final CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper + cmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper; + private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; + + @Value("${notification.enabled:true}") + private boolean notificationFeatureEnabled; + + @Value("${ncmp.model-loader.subscription:false}") + private boolean subscriptionModelLoaderEnabled; + + /** + * Consume subscription response event. + * + * @param cmSubscriptionDmiOutConsumerRecord the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", + containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") + public void consumeDmiOutEvent( + final ConsumerRecord cmSubscriptionDmiOutConsumerRecord) { + final CloudEvent cloudEvent = cmSubscriptionDmiOutConsumerRecord.value(); + final String eventType = cmSubscriptionDmiOutConsumerRecord.value().getType(); + final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent = + toTargetEvent(cloudEvent, CmSubscriptionDmiOutEvent.class); + final String clientId = cmSubscriptionDmiOutEvent.getData().getClientId(); + log.info("subscription event response of clientId: {} is received.", clientId); + final String subscriptionName = cmSubscriptionDmiOutEvent.getData().getSubscriptionName(); + final String subscriptionEventId = clientId + subscriptionName; + boolean createOutcomeResponse = true; + if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { + final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); + dmiNames.remove(cmSubscriptionDmiOutEvent.getData().getDmiName()); + forwardedSubscriptionEventCache.put(subscriptionEventId, dmiNames, + ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); + createOutcomeResponse = forwardedSubscriptionEventCache.get(subscriptionEventId).isEmpty(); + } + if (subscriptionModelLoaderEnabled) { + updateSubscriptionEvent(cmSubscriptionDmiOutEvent); + } + if (createOutcomeResponse + && notificationFeatureEnabled) { + + final CmSubscriptionEvent cmSubscriptionEvent = new CmSubscriptionEvent(); + cmSubscriptionEvent.setClientId(cmSubscriptionDmiOutEvent.getData().getClientId()); + cmSubscriptionEvent.setSubscriptionName(cmSubscriptionDmiOutEvent.getData().getSubscriptionName()); + + cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent, eventType); + forwardedSubscriptionEventCache.remove(subscriptionEventId); + } + } + + private void updateSubscriptionEvent(final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent) { + final YangModelSubscriptionEvent yangModelSubscriptionEvent = + cmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper + .toYangModelSubscriptionEvent(cmSubscriptionDmiOutEvent); + subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java new file mode 100644 index 000000000..e2999950e --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper.java @@ -0,0 +1,56 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription; + +import java.util.List; +import java.util.stream.Collectors; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper { + + @Mapping(source = "data.clientId", target = "clientId") + @Mapping(source = "data.subscriptionName", target = "subscriptionName") + @Mapping(source = "data.subscriptionStatus", target = "predicates.targetCmHandles", + qualifiedByName = "mapSubscriptionStatusToCmHandleTargets") + YangModelSubscriptionEvent toYangModelSubscriptionEvent( + CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent); + + /** + * Maps SubscriptionStatus to list of TargetCmHandle. + * + * @param subscriptionStatus as a list + * @return TargetCmHandle list + */ + @Named("mapSubscriptionStatusToCmHandleTargets") + default List mapSubscriptionStatusToCmHandleTargets( + List subscriptionStatus) { + return subscriptionStatus.stream().map(status -> new YangModelSubscriptionEvent.TargetCmHandle(status.getId(), + org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus.fromString( + status.getStatus().value()), + status.getDetails())).collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java new file mode 100644 index 000000000..0de04ade7 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java @@ -0,0 +1,105 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; +import org.onap.cps.ncmp.api.models.CmSubscriptionStatus; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfo; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfoDetail; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent; +import org.onap.cps.spi.exceptions.DataValidationException; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper { + + @Mapping(source = "cmSubscriptionStatus", target = "data.additionalInfo", + qualifiedByName = "mapCmSubscriptionStatusToAdditionalInfo") + CmSubscriptionNcmpOutEvent toCmSubscriptionNcmpOutEvent(CmSubscriptionEvent cmSubscriptionEvent); + + /** + * Maps list of SubscriptionStatus to an AdditionalInfo. + * + * @param cmSubscriptionStatusList containing details + * @return an AdditionalInfo + */ + @Named("mapCmSubscriptionStatusToAdditionalInfo") + default AdditionalInfo mapCmSubscriptionStatusToAdditionalInfo( + final List cmSubscriptionStatusList) { + if (cmSubscriptionStatusList == null || cmSubscriptionStatusList.isEmpty()) { + throw new DataValidationException("Invalid cmSubscriptionStatusList", + "CmSubscriptionStatus list cannot be null or empty"); + } + + final Map> rejectedSubscriptionsPerDetails = + getSubscriptionsPerDetails(cmSubscriptionStatusList, SubscriptionStatus.REJECTED); + final Map> rejectedCmHandlesPerDetails = + getCmHandlesPerDetails(rejectedSubscriptionsPerDetails); + final List rejectedCmHandles = getAdditionalInfoDetailList(rejectedCmHandlesPerDetails); + + final Map> pendingSubscriptionsPerDetails = + getSubscriptionsPerDetails(cmSubscriptionStatusList, SubscriptionStatus.PENDING); + final Map> pendingCmHandlesPerDetails = + getCmHandlesPerDetails(pendingSubscriptionsPerDetails); + final List pendingCmHandles = getAdditionalInfoDetailList(pendingCmHandlesPerDetails); + + final AdditionalInfo additionalInfo = new AdditionalInfo(); + additionalInfo.setRejected(rejectedCmHandles); + additionalInfo.setPending(pendingCmHandles); + + return additionalInfo; + } + + private static Map> getSubscriptionsPerDetails( + final List cmSubscriptionStatusList, final SubscriptionStatus status) { + return cmSubscriptionStatusList.stream() + .filter(subscriptionStatus -> subscriptionStatus.getStatus() == status) + .collect(Collectors.groupingBy(CmSubscriptionStatus::getDetails)); + } + + private static Map> getCmHandlesPerDetails( + final Map> cmSubscriptionsPerDetails) { + return cmSubscriptionsPerDetails.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> entry.getValue().stream() + .map(CmSubscriptionStatus::getId) + .collect(Collectors.toList()) + )); + } + + private static List getAdditionalInfoDetailList( + final Map> cmHandlesPerDetails) { + return cmHandlesPerDetails.entrySet().stream() + .map(entry -> { + final AdditionalInfoDetail detail = new AdditionalInfoDetail(); + detail.setDetails(entry.getKey()); + detail.setTargets(entry.getValue()); + return detail; + }).collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumer.java new file mode 100644 index 000000000..7227af91a --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumer.java @@ -0,0 +1,96 @@ +/* + * ============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.deprecated.cmsubscription; + +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 io.cloudevents.CloudEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionNcmpInEventConsumer { + + private final CmSubscriptionNcmpInEventForwarder cmSubscriptionNcmpInEventForwarder; + private final CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper; + private final SubscriptionPersistence subscriptionPersistence; + + @Value("${notification.enabled:true}") + private boolean notificationFeatureEnabled; + + @Value("${ncmp.model-loader.subscription:false}") + private boolean subscriptionModelLoaderEnabled; + + /** + * Consume the specified event. + * + * @param subscriptionEventConsumerRecord the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.subscription-topic}", + containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") + public void consumeSubscriptionEvent(final ConsumerRecord subscriptionEventConsumerRecord) { + final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value(); + final String eventType = subscriptionEventConsumerRecord.value().getType(); + final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent = + toTargetEvent(cloudEvent, CmSubscriptionNcmpInEvent.class); + final String eventDatastore = cmSubscriptionNcmpInEvent.getData().getPredicates().getDatastore(); + if (!eventDatastore.equals(PASSTHROUGH_RUNNING.getDatastoreName()) || eventDatastore.equals( + PASSTHROUGH_OPERATIONAL.getDatastoreName())) { + throw new UnsupportedOperationException( + "passthrough datastores are currently only supported for event subscriptions"); + } + if ("CM".equals(cmSubscriptionNcmpInEvent.getData().getDataType().getDataCategory())) { + if (subscriptionModelLoaderEnabled) { + persistSubscriptionEvent(cmSubscriptionNcmpInEvent); + } + if ("subscriptionCreated".equals(cloudEvent.getType())) { + log.info("Subscription for ClientID {} with name {} ...", + cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID(), + cmSubscriptionNcmpInEvent.getData().getSubscription().getName()); + if (notificationFeatureEnabled) { + cmSubscriptionNcmpInEventForwarder.forwardCreateSubscriptionEvent(cmSubscriptionNcmpInEvent, + eventType); + } + } + } else { + log.trace("Non-CM subscription event ignored"); + } + } + + private void persistSubscriptionEvent(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent) { + final YangModelSubscriptionEvent yangModelSubscriptionEvent = + cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(cmSubscriptionNcmpInEvent); + subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarder.java new file mode 100644 index 000000000..ae192c439 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarder.java @@ -0,0 +1,204 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription; + +import com.hazelcast.map.IMap; +import io.cloudevents.CloudEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.events.EventsPublisher; +import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; +import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper; +import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionNcmpInEventForwarder { + + private static final Pattern REGEX_TO_EXTRACT_DOMAIN_FROM_URL_EXCLUDING_PORT = + Pattern.compile("http[s]?:\\/\\/(?:www\\.)?([^\\/:]+):{0,1}[0-9]{0,5}"); + + private final InventoryPersistence inventoryPersistence; + private final EventsPublisher eventsPublisher; + private final IMap> forwardedSubscriptionEventCache; + private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; + private final CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper; + private final CmSubscriptionEventCloudMapper cmSubscriptionEventCloudMapper; + private final CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper + cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper; + private final SubscriptionPersistence subscriptionPersistence; + private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + @Value("${app.ncmp.avc.subscription-forward-topic-prefix}") + private String dmiAvcSubscriptionTopicPrefix; + + @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms:30000}") + private int dmiResponseTimeoutInMs; + + /** + * Forward subscription event. + * + * @param cmSubscriptionNcmpInEvent the event to be forwarded + */ + public void forwardCreateSubscriptionEvent(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, + final String eventType) { + final List cmHandleTargets = cmSubscriptionNcmpInEvent.getData().getPredicates().getTargets(); + if (cmHandleTargets == null || cmHandleTargets.isEmpty() || cmHandleTargets.stream() + .anyMatch(id -> (id).contains("*"))) { + throw new UnsupportedOperationException( + "CMHandle targets are required. \"Wildcard\" operations are not yet supported"); + } + final Collection yangModelCmHandles = + inventoryPersistence.getYangModelCmHandles(cmHandleTargets); + final Map>> dmiPropertiesPerCmHandleIdPerServiceName = + DmiServiceNameOrganizer.getDmiPropertiesPerCmHandleIdPerServiceName(yangModelCmHandles); + findDmisAndRespond(cmSubscriptionNcmpInEvent, eventType, cmHandleTargets, + dmiPropertiesPerCmHandleIdPerServiceName); + } + + private void findDmisAndRespond(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, final String eventType, + final List cmHandleTargetsAsStrings, + final Map>> dmiPropertiesPerCmHandleIdPerServiceName) { + + final CmSubscriptionEvent cmSubscriptionEvent = new CmSubscriptionEvent(); + cmSubscriptionEvent.setSubscriptionName(cmSubscriptionNcmpInEvent.getData().getSubscription().getName()); + cmSubscriptionEvent.setClientId(cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID()); + + final List cmHandlesThatExistsInDb = + dmiPropertiesPerCmHandleIdPerServiceName.entrySet().stream().map(Map.Entry::getValue).map(Map::keySet) + .flatMap(Set::stream).collect(Collectors.toList()); + + final List targetCmHandlesDoesNotExistInDb = new ArrayList<>(cmHandleTargetsAsStrings); + targetCmHandlesDoesNotExistInDb.removeAll(cmHandlesThatExistsInDb); + + final Set dmisToRespond = new HashSet<>(dmiPropertiesPerCmHandleIdPerServiceName.keySet()); + + if (dmisToRespond.isEmpty() || !targetCmHandlesDoesNotExistInDb.isEmpty()) { + updatesCmHandlesToRejectedAndPersistSubscriptionEvent(cmSubscriptionNcmpInEvent, + targetCmHandlesDoesNotExistInDb); + } + if (dmisToRespond.isEmpty()) { + cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent, + "subscriptionCreatedStatus"); + } else { + startResponseTimeout(cmSubscriptionEvent, dmisToRespond); + final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent = + cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.toCmSubscriptionDmiInEvent( + cmSubscriptionNcmpInEvent); + forwardEventToDmis(dmiPropertiesPerCmHandleIdPerServiceName, cmSubscriptionDmiInEvent, eventType); + } + } + + private void startResponseTimeout(final CmSubscriptionEvent cmSubscriptionEvent, + final Set dmisToRespond) { + final String subscriptionClientId = cmSubscriptionEvent.getClientId(); + final String subscriptionName = cmSubscriptionEvent.getSubscriptionName(); + final String subscriptionEventId = subscriptionClientId + subscriptionName; + + forwardedSubscriptionEventCache.put(subscriptionEventId, dmisToRespond, + ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); + final ResponseTimeoutTask responseTimeoutTask = + new ResponseTimeoutTask(forwardedSubscriptionEventCache, cmSubscriptionNcmpOutEventPublisher, + cmSubscriptionEvent); + + executorService.schedule(responseTimeoutTask, dmiResponseTimeoutInMs, TimeUnit.MILLISECONDS); + } + + private void forwardEventToDmis(final Map>> dmiNameCmHandleMap, + final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent, final String eventType) { + dmiNameCmHandleMap.forEach((dmiName, cmHandlePropertiesMap) -> { + final List cmHandleTargets = cmHandlePropertiesMap.entrySet().stream().map( + cmHandleAndProperties -> { + final CmHandle cmHandle = new CmHandle(); + cmHandle.setId(cmHandleAndProperties.getKey()); + cmHandle.setAdditionalProperties(cmHandleAndProperties.getValue()); + return cmHandle; + }).collect(Collectors.toList()); + + cmSubscriptionDmiInEvent.getData().getPredicates().setTargets(cmHandleTargets); + final String dmiNameSuffix = toValidTopicSuffix(dmiName); + final String eventKey = createEventKey(cmSubscriptionDmiInEvent, dmiNameSuffix); + final String dmiAvcSubscriptionTopic = dmiAvcSubscriptionTopicPrefix + dmiNameSuffix; + + final CloudEvent cmSubscriptionDmiInCloudEvent = + cmSubscriptionEventCloudMapper.toCloudEvent(cmSubscriptionDmiInEvent, eventKey, eventType); + eventsPublisher.publishCloudEvent(dmiAvcSubscriptionTopic, eventKey, cmSubscriptionDmiInCloudEvent); + }); + } + + private String createEventKey(final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent, final String dmiName) { + return cmSubscriptionDmiInEvent.getData().getSubscription().getClientID() + "-" + + cmSubscriptionDmiInEvent.getData().getSubscription().getName() + "-" + dmiName; + } + + private void updatesCmHandlesToRejectedAndPersistSubscriptionEvent( + final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, + final List targetCmHandlesDoesNotExistInDb) { + final YangModelSubscriptionEvent yangModelSubscriptionEvent = + cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(cmSubscriptionNcmpInEvent); + yangModelSubscriptionEvent.getPredicates() + .setTargetCmHandles(findRejectedCmHandles(targetCmHandlesDoesNotExistInDb, yangModelSubscriptionEvent)); + subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); + } + + private static List findRejectedCmHandles( + final List targetCmHandlesDoesNotExistInDb, + final YangModelSubscriptionEvent yangModelSubscriptionEvent) { + return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles().stream() + .filter(targetCmHandle -> targetCmHandlesDoesNotExistInDb.contains(targetCmHandle.getCmHandleId())) + .map(target -> new YangModelSubscriptionEvent.TargetCmHandle(target.getCmHandleId(), + SubscriptionStatus.REJECTED, "Targets not found")) + .collect(Collectors.toList()); + } + + /* + CPS-1979 : DmiName can be a URL , which is not a valid topic name. + Hence just taking the domain name(excluding port) information to be part of the topic name. + */ + private String toValidTopicSuffix(final String dmiName) { + final Matcher matcher = REGEX_TO_EXTRACT_DOMAIN_FROM_URL_EXCLUDING_PORT.matcher(dmiName); + return matcher.find() ? matcher.group(1) : dmiName; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapper.java new file mode 100644 index 000000000..852d5510c --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapper.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription; + +import java.util.List; +import java.util.stream.Collectors; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionNcmpInEventMapper { + + @Mapping(source = "data.subscription.clientID", target = "clientId") + @Mapping(source = "data.subscription.name", target = "subscriptionName") + @Mapping(source = "data.predicates.targets", target = "predicates.targetCmHandles", + qualifiedByName = "mapTargetsToCmHandleTargets") + @Mapping(source = "data.predicates.datastore", target = "predicates.datastore") + YangModelSubscriptionEvent toYangModelSubscriptionEvent(CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent); + + /** + * Maps list of Targets to list of TargetCmHandle. + * + * @param targets list of objects + * @return TargetCmHandle list + */ + @Named("mapTargetsToCmHandleTargets") + default List mapTargetsToCmHandleTargets(List targets) { + return targets.stream().map(YangModelSubscriptionEvent.TargetCmHandle::new) + .collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java new file mode 100644 index 000000000..a87508ce5 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent; + +@Mapper(componentModel = "spring") +public interface CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper { + + @Mapping(target = "data.predicates.targets", ignore = true) + CmSubscriptionDmiInEvent toCmSubscriptionDmiInEvent( + CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent); + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java new file mode 100644 index 000000000..8a3c44da4 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java @@ -0,0 +1,146 @@ +/* + * ============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.deprecated.cmsubscription; + +import static org.onap.cps.ncmp.api.NcmpResponseStatus.PARTIALLY_APPLIED_SUBSCRIPTION; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_NOT_APPLICABLE; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_PENDING; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESSFULLY_APPLIED_SUBSCRIPTION; +import static org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus.ACCEPTED; +import static org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus.PENDING; +import static org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus.REJECTED; + +import io.cloudevents.CloudEvent; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.NcmpResponseStatus; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistence; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.events.EventsPublisher; +import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; +import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper; +import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; +import org.onap.cps.ncmp.api.models.CmSubscriptionStatus; +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class CmSubscriptionNcmpOutEventPublisher { + + private final SubscriptionPersistence subscriptionPersistence; + + private final EventsPublisher outcomeEventsPublisher; + + private final CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper + cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper; + + private final SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper; + + @Value("${app.ncmp.avc.subscription-outcome-topic:subscription-response}") + private String subscriptionOutcomeEventTopic; + + /** + * This is for construction of outcome message to be published for client apps. + * + * @param cmSubscriptionEvent event produced by Dmi Plugin + */ + public void sendResponse(final CmSubscriptionEvent cmSubscriptionEvent, final String eventType) { + final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent = + formCmSubscriptionNcmpOutEvent(cmSubscriptionEvent); + final String subscriptionClientId = cmSubscriptionEvent.getClientId(); + final String subscriptionName = cmSubscriptionEvent.getSubscriptionName(); + final String subscriptionEventId = subscriptionClientId + subscriptionName; + final CloudEvent subscriptionOutcomeCloudEvent = + subscriptionOutcomeCloudMapper.toCloudEvent(cmSubscriptionNcmpOutEvent, + subscriptionEventId, eventType); + outcomeEventsPublisher.publishCloudEvent(subscriptionOutcomeEventTopic, + subscriptionEventId, subscriptionOutcomeCloudEvent); + } + + private CmSubscriptionNcmpOutEvent formCmSubscriptionNcmpOutEvent( + final CmSubscriptionEvent cmSubscriptionEvent) { + final Map> cmHandleIdToStatusAndDetailsAsMap = + DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode( + subscriptionPersistence.getCmHandlesForSubscriptionEvent( + cmSubscriptionEvent.getClientId(), + cmSubscriptionEvent.getSubscriptionName())); + final List cmSubscriptionStatusList = + mapCmHandleIdStatusDetailsMapToSubscriptionStatusList(cmHandleIdToStatusAndDetailsAsMap); + cmSubscriptionEvent.setCmSubscriptionStatus(cmSubscriptionStatusList); + return fromCmSubscriptionEvent(cmSubscriptionEvent, + decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap)); + } + + private static List mapCmHandleIdStatusDetailsMapToSubscriptionStatusList( + final Map> cmHandleIdToStatusAndDetailsAsMap) { + return cmHandleIdToStatusAndDetailsAsMap.entrySet() + .stream().map(entryset -> { + final CmSubscriptionStatus cmSubscriptionStatus = new CmSubscriptionStatus(); + final String cmHandleId = entryset.getKey(); + final Map statusAndDetailsMap = entryset.getValue(); + final String status = statusAndDetailsMap.get("status"); + final String details = statusAndDetailsMap.get("details"); + cmSubscriptionStatus.setId(cmHandleId); + cmSubscriptionStatus.setStatus(SubscriptionStatus.fromString(status)); + cmSubscriptionStatus.setDetails(details); + return cmSubscriptionStatus; + }).toList(); + } + + private NcmpResponseStatus decideOnNcmpEventResponseCodeForSubscription( + final Map> cmHandleIdToStatusAndDetailsAsMap) { + + if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, ACCEPTED)) { + return SUCCESSFULLY_APPLIED_SUBSCRIPTION; + } + if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, REJECTED)) { + return SUBSCRIPTION_NOT_APPLICABLE; + } + if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, PENDING)) { + return SUBSCRIPTION_PENDING; + } + return PARTIALLY_APPLIED_SUBSCRIPTION; + } + + private boolean allTargetsHaveStatus(final Map> cmHandleIdToStatusAndDetailsAsMap, + final SubscriptionStatus subscriptionStatus) { + return cmHandleIdToStatusAndDetailsAsMap.values().stream() + .allMatch(entryset -> entryset.containsValue(subscriptionStatus.toString())); + } + + private CmSubscriptionNcmpOutEvent fromCmSubscriptionEvent( + final CmSubscriptionEvent cmSubscriptionEvent, + final NcmpResponseStatus ncmpResponseStatus) { + + final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent = + cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.toCmSubscriptionNcmpOutEvent( + cmSubscriptionEvent); + cmSubscriptionNcmpOutEvent.getData().setStatusCode(Integer.parseInt(ncmpResponseStatus.getCode())); + cmSubscriptionNcmpOutEvent.getData().setStatusMessage(ncmpResponseStatus.getMessage()); + + return cmSubscriptionNcmpOutEvent; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ResponseTimeoutTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ResponseTimeoutTask.java new file mode 100644 index 000000000..8832ca3d0 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ResponseTimeoutTask.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription; + +import com.hazelcast.map.IMap; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.models.CmSubscriptionEvent; + +@Slf4j +@RequiredArgsConstructor +public class ResponseTimeoutTask implements Runnable { + + private final IMap> forwardedSubscriptionEventCache; + private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher; + private final CmSubscriptionEvent cmSubscriptionEvent; + + @Override + public void run() { + generateTimeoutResponse(); + } + + private void generateTimeoutResponse() { + final String subscriptionClientId = cmSubscriptionEvent.getClientId(); + final String subscriptionName = cmSubscriptionEvent.getSubscriptionName(); + final String subscriptionEventId = subscriptionClientId + subscriptionName; + if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { + cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent, + "subscriptionCreatedStatus"); + forwardedSubscriptionEventCache.remove(subscriptionEventId); + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistence.java deleted file mode 100644 index 8092e3951..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistence.java +++ /dev/null @@ -1,50 +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.subscriptions; - -import java.util.Collection; -import org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.spi.model.DataNode; - -public interface SubscriptionPersistence extends NcmpPersistence { - - /** - * Save subscription Event. - * - * @param yangModelSubscriptionEvent subscription Event as Yang Model. - */ - void saveSubscriptionEvent(YangModelSubscriptionEvent yangModelSubscriptionEvent); - - /** - * Get data nodes. - * - * @return the DataNode as collection. - */ - Collection getDataNodesForSubscriptionEvent(); - - /** - * Get data nodes by xpath. - * - * @return the DataNode as collection. - */ - Collection getCmHandlesForSubscriptionEvent(String clientId, String subscriptionName); -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceImpl.java deleted file mode 100644 index dd0c20d59..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceImpl.java +++ /dev/null @@ -1,199 +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.subscriptions; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.api.CpsDataService; -import org.onap.cps.api.CpsModuleService; -import org.onap.cps.ncmp.api.impl.inventory.NcmpPersistenceImpl; -import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent; -import org.onap.cps.spi.FetchDescendantsOption; -import org.onap.cps.spi.model.DataNode; -import org.onap.cps.spi.utils.CpsValidator; -import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -public class SubscriptionPersistenceImpl extends NcmpPersistenceImpl implements SubscriptionPersistence { - - private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions"; - private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry"; - - public SubscriptionPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService, - final CpsModuleService cpsModuleService, final CpsValidator cpsValidator) { - super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator); - } - - - @Override - public void saveSubscriptionEvent(final YangModelSubscriptionEvent yangModelSubscriptionEvent) { - final String clientId = yangModelSubscriptionEvent.getClientId(); - final String subscriptionName = yangModelSubscriptionEvent.getSubscriptionName(); - - final Collection dataNodes = cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, - SUBSCRIPTION_ANCHOR_NAME, SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); - - if (isSubscriptionRegistryEmptyOrNonExist(dataNodes, clientId, subscriptionName)) { - saveSubscriptionEventYangModel(createSubscriptionEventJsonData( - jsonObjectMapper.asJsonString(yangModelSubscriptionEvent))); - } else { - findDeltaCmHandlesAddOrUpdateInDatabase(yangModelSubscriptionEvent, clientId, subscriptionName, dataNodes); - } - } - - private void findDeltaCmHandlesAddOrUpdateInDatabase(final YangModelSubscriptionEvent yangModelSubscriptionEvent, - final String clientId, final String subscriptionName, - final Collection dataNodes) { - final Map> cmHandleIdToStatusAndDetailsAsMapNew = - extractCmHandleFromYangModelAsMap(yangModelSubscriptionEvent); - final Map> cmHandleIdToStatusAndDetailsAsMapOriginal = - DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode(dataNodes); - - final Map> newTargetCmHandles = mapDifference(cmHandleIdToStatusAndDetailsAsMapNew, - cmHandleIdToStatusAndDetailsAsMapOriginal); - traverseCmHandleList(newTargetCmHandles, clientId, subscriptionName, true); - - final Map> existingTargetCmHandles = - mapDifference(cmHandleIdToStatusAndDetailsAsMapNew, newTargetCmHandles); - traverseCmHandleList(existingTargetCmHandles, clientId, subscriptionName, false); - } - - private static Map> extractCmHandleFromYangModelAsMap( - final YangModelSubscriptionEvent yangModelSubscriptionEvent) { - return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles() - .stream().collect( - HashMap::new, - (result, cmHandle) -> { - final String cmHandleId = cmHandle.getCmHandleId(); - final SubscriptionStatus status = cmHandle.getStatus(); - final String details = cmHandle.getDetails(); - - if (cmHandleId != null && status != null) { - result.put(cmHandleId, new HashMap<>()); - result.get(cmHandleId).put("status", status.toString()); - result.get(cmHandleId).put("details", details == null ? "" : details); - } - }, - HashMap::putAll - ); - } - - private void traverseCmHandleList(final Map> cmHandleMap, - final String clientId, - final String subscriptionName, - final boolean isAddListElementOperation) { - final List cmHandleList = targetCmHandlesAsList(cmHandleMap); - for (final YangModelSubscriptionEvent.TargetCmHandle targetCmHandle : cmHandleList) { - final String targetCmHandleAsJson = - createTargetCmHandleJsonData(jsonObjectMapper.asJsonString(targetCmHandle)); - addOrReplaceCmHandlePredicateListElement(targetCmHandleAsJson, clientId, subscriptionName, - isAddListElementOperation); - } - } - - private boolean isSubscriptionRegistryEmptyOrNonExist(final Collection dataNodes, - final String clientId, final String subscriptionName) { - final Optional dataNodeFirst = dataNodes.stream().findFirst(); - return ((dataNodeFirst.isPresent() && dataNodeFirst.get().getChildDataNodes().isEmpty()) - || getCmHandlesForSubscriptionEvent(clientId, subscriptionName).isEmpty()); - } - - private void addOrReplaceCmHandlePredicateListElement(final String targetCmHandleAsJson, - final String clientId, - final String subscriptionName, - final boolean isAddListElementOperation) { - if (isAddListElementOperation) { - log.info("targetCmHandleAsJson to be added into DB {}", targetCmHandleAsJson); - cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP); - } else { - log.info("targetCmHandleAsJson to be updated into DB {}", targetCmHandleAsJson); - cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP); - } - } - - private void saveSubscriptionEventYangModel(final String subscriptionEventJsonData) { - log.info("SubscriptionEventJsonData to be saved into DB {}", subscriptionEventJsonData); - cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - SUBSCRIPTION_REGISTRY_PARENT, subscriptionEventJsonData, NO_TIMESTAMP); - } - - @Override - public Collection getDataNodesForSubscriptionEvent() { - return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); - } - - @Override - public Collection getCmHandlesForSubscriptionEvent(final String clientId, final String subscriptionName) { - return cpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - List.of(createCmHandleXpath(clientId, subscriptionName)), - FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); - } - - private static List targetCmHandlesAsList( - final Map> newCmHandles) { - return newCmHandles.entrySet().stream().map(entry -> { - final String cmHandleId = entry.getKey(); - final Map statusAndDetailsMap = entry.getValue(); - final String status = statusAndDetailsMap.get("status"); - final String details = statusAndDetailsMap.get("details"); - return new YangModelSubscriptionEvent.TargetCmHandle(cmHandleId, SubscriptionStatus.fromString(status), - details); - }).collect(Collectors.toList()); - } - - private static String createSubscriptionEventJsonData(final String yangModelSubscriptionAsJson) { - return "{\"subscription\":[" + yangModelSubscriptionAsJson + "]}"; - } - - private static String createTargetCmHandleJsonData(final String targetCmHandleAsJson) { - return "{\"targetCmHandles\":[" + targetCmHandleAsJson + "]}"; - } - - private static String createCmHandleXpathPredicates(final String clientId, final String subscriptionName) { - return "/subscription-registry/subscription[@clientID='" + clientId - + "' and @subscriptionName='" + subscriptionName + "']/predicates"; - } - - private static String createCmHandleXpath(final String clientId, final String subscriptionName) { - return "/subscription-registry/subscription[@clientID='" + clientId - + "' and @subscriptionName='" + subscriptionName + "']"; - } - - private static Map> mapDifference(final Map> left, - final Map> right) { - final Map> difference = new HashMap<>(); - difference.putAll(left); - difference.putAll(right); - difference.entrySet().removeAll(right.entrySet()); - return difference; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionStatus.java deleted file mode 100644 index 63ab102d1..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionStatus.java +++ /dev/null @@ -1,49 +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.subscriptions; - - -public enum SubscriptionStatus { - ACCEPTED("ACCEPTED"), - REJECTED("REJECTED"), - PENDING("PENDING"); - - private final String subscriptionStatusValue; - - SubscriptionStatus(final String subscriptionStatusValue) { - this.subscriptionStatusValue = subscriptionStatusValue; - } - - /** - * Finds the value of the given enum. - * - * @param statusValue value of the enum - * @return a SubscriptionStatus - */ - public static SubscriptionStatus fromString(final String statusValue) { - for (final SubscriptionStatus subscriptionStatusType : SubscriptionStatus.values()) { - if (subscriptionStatusType.subscriptionStatusValue.equalsIgnoreCase(statusValue)) { - return subscriptionStatusType; - } - } - return null; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelSubscriptionEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelSubscriptionEvent.java index 866bfd4e7..a6cfa7bb7 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelSubscriptionEvent.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelSubscriptionEvent.java @@ -31,7 +31,7 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus; /** * Subscription event model to persist data into DB. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java index 5541a01bd..c56912376 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java @@ -25,7 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus; @JsonInclude(JsonInclude.Include.NON_NULL) @Getter diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/SubscriptionEventResponse.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/SubscriptionEventResponse.java index 05663a55d..cabd8683f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/SubscriptionEventResponse.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/SubscriptionEventResponse.java @@ -25,7 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Map; import lombok.Getter; import lombok.Setter; -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus; @JsonInclude(JsonInclude.Include.NON_NULL) @Getter diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceSpec.groovy new file mode 100644 index 000000000..da1a12235 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/deprecated/subscriptions/SubscriptionPersistenceSpec.groovy @@ -0,0 +1,99 @@ +/* + * ============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.deprecated.subscriptions + +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.api.CpsDataService +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent +import org.onap.cps.spi.model.DataNodeBuilder +import org.onap.cps.utils.JsonObjectMapper +import org.onap.cps.api.CpsModuleService +import org.onap.cps.spi.utils.CpsValidator +import spock.lang.Specification + +class SubscriptionPersistenceSpec extends Specification { + + private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions"; + private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry"; + private static final String SUBSCRIPTION_REGISTRY_PREDICATES_XPATH = "/subscription-registry/subscription[@clientID='some-client-id' and @subscriptionName='some-subscription-name']/predicates"; + + def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) + def mockCpsDataService = Mock(CpsDataService) + def mockCpsModuleService = Mock(CpsModuleService) + def mockCpsValidator = Mock(CpsValidator) + + def objectUnderTest = new SubscriptionPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService, + mockCpsModuleService, mockCpsValidator) + + def predicates = new YangModelSubscriptionEvent.Predicates(datastore: 'some-datastore', + targetCmHandles: [new YangModelSubscriptionEvent.TargetCmHandle('cmhandle1'), + new YangModelSubscriptionEvent.TargetCmHandle('cmhandle2')]) + def yangModelSubscriptionEvent = new YangModelSubscriptionEvent(clientId: 'some-client-id', + subscriptionName: 'some-subscription-name', tagged: true, topic: 'some-topic', predicates: predicates) + + def 'save a subscription event as yang model into db for the #scenarios' () { + given: 'a blank data node that exist in db' + def blankDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) + .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry').build() + and: 'cps data service return an empty data node' + mockCpsDataService.getDataNodes(*_) >> [blankDataNode] + when: 'the yangModelSubscriptionEvent is saved into db' + objectUnderTest.saveSubscriptionEvent(yangModelSubscriptionEvent) + then: 'the cpsDataService save operation is called with the correct data' + 1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + SUBSCRIPTION_REGISTRY_PARENT, + '{"subscription":[{' + + '"topic":"some-topic",' + + '"predicates":{"datastore":"some-datastore","targetCmHandles":[{"cmHandleId":"cmhandle1","status":"PENDING","details":"Subscription forwarded to dmi plugin"},' + + '{"cmHandleId":"cmhandle2","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]},' + + '"clientID":"some-client-id","subscriptionName":"some-subscription-name","isTagged":true}]}', + NO_TIMESTAMP) + } + + def 'add or replace cm handle list element into db' () { + given: 'a data node with child node exist in db' + def leaves1 = [status:'REJECTED', cmHandleId:'cmhandle1', details:'Cm handle does not exist'] as Map + def childDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) + .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') + .withLeaves(leaves1).build() + def engagedDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) + .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry') + .withChildDataNodes([childDataNode]).build() + and: 'cps data service return data node including a child data node' + mockCpsDataService.getDataNodes(*_) >> [engagedDataNode] + and: 'cps data service return data node for querying by xpaths' + mockCpsDataService.getDataNodesForMultipleXpaths(*_) >> [engagedDataNode] + when: 'the yang model subscription event is saved into db' + objectUnderTest.saveSubscriptionEvent(yangModelSubscriptionEvent) + then: 'the cpsDataService save non-existing cm handle with the correct data' + 1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + SUBSCRIPTION_REGISTRY_PREDICATES_XPATH, '{"targetCmHandles":[{"cmHandleId":"cmhandle2","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]}', + NO_TIMESTAMP) + and: 'the cpsDataService update existing cm handle with the correct data' + 1 * mockCpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, + SUBSCRIPTION_REGISTRY_PREDICATES_XPATH, '{"targetCmHandles":[{"cmHandleId":"cmhandle1","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]}', + NO_TIMESTAMP) + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy deleted file mode 100644 index b08b51ba2..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.cmsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class ClientCmSubscriptionNcmpInEventMapperSpec extends Specification { - - CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map clients subscription event to ncmps subscription event'() { - given: 'a Subscription Event' - def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') - def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) - when: 'the client event is mapped to a ncmp subscription event' - def result = objectUnderTest.toCmSubscriptionDmiInEvent(testEventToMap) - then: 'the resulting ncmp subscription event contains the correct clientId' - assert result.getData().getSubscription().getClientID() == "SCO-9989752" - and: 'subscription name' - assert result.getData().getSubscription().getName() == "cm-subscription-001" - and: 'is tagged value is false' - assert result.getData().getSubscription().getIsTagged() == false - and: 'data category is CM' - assert result.getData().getDataType().getDataCategory() == 'CM' - and: 'predicate targets is null' - assert result.getData().getPredicates().getTargets() == [] - and: 'datastore is passthrough-running' - assert result.getData().getPredicates().getDatastore() == 'ncmp-datastore:passthrough-running' - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy deleted file mode 100644 index 95dee77bf..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy +++ /dev/null @@ -1,140 +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.cmsubscription - -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME - -import com.fasterxml.jackson.databind.ObjectMapper -import com.hazelcast.map.IMap -import io.cloudevents.CloudEvent -import io.cloudevents.core.builder.CloudEventBuilder -import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistenceImpl -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.spi.model.DataNodeBuilder -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec { - - @Autowired - JsonObjectMapper jsonObjectMapper - - @Autowired - ObjectMapper objectMapper - - IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) - def mockSubscriptionPersistence = Mock(SubscriptionPersistenceImpl) - def mockSubscriptionEventResponseMapper = Mock(CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper) - def mockCmSubscriptionNcmpOutEventPublisher = Mock(CmSubscriptionNcmpOutEventPublisher) - - def objectUnderTest = new CmSubscriptionDmiOutEventConsumer(mockForwardedSubscriptionEventCache, - mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockCmSubscriptionNcmpOutEventPublisher) - - def 'Consume dmi out event where all DMIs have responded'() { - given: 'a consumer record including cloud event having dmi out event' - def dmiOutConsumerRecord = getDmiOutConsumerRecord() - and: 'notifications are enabled' - objectUnderTest.notificationFeatureEnabled = notificationEnabled - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled - and: 'subscription persistence service returns data node includes no pending cm handle' - mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [getDataNode()] - when: 'the valid event is consumed' - objectUnderTest.consumeDmiOutEvent(dmiOutConsumerRecord) - then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' - 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['some-dmi-name'] as Set) - and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> ([] as Set) - and: 'the response event is map to yang model' - numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) - and: 'the response event is persisted into the db' - numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) - and: 'the subscription event is removed from the map' - numberOfTimeToRemove * mockForwardedSubscriptionEventCache.remove('SCO-9989752cm-subscription-001') - and: 'a response outcome has been created' - numberOfTimeToResponse * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(_, 'subscriptionCreated') - where: 'the following values are used' - scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist || numberOfTimeToRemove || numberOfTimeToResponse - 'Both model loader and notification are enabled' | true | true || 1 || 1 || 1 - 'Both model loader and notification are disabled' | false | false || 0 || 0 || 0 - 'Model loader enabled and notification disabled' | true | false || 1 || 0 || 0 - 'Model loader disabled and notification enabled' | false | true || 0 || 1 || 1 - } - - def 'Consume dmi out event where another DMI has not yet responded'() { - given: 'a subscription event response and notifications are enabled' - objectUnderTest.notificationFeatureEnabled = notificationEnabled - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled - when: 'the valid event is consumed' - objectUnderTest.consumeDmiOutEvent(getDmiOutConsumerRecord()) - then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' - 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['responded-dmi', 'non-responded-dmi'] as Set) - and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' - 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['non-responded-dmi'] as Set) - and: 'the response event is map to yang model' - numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) - and: 'the response event is persisted into the db' - numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) - and: 'the subscription event is removed from the map' - and: 'the subscription event is not removed from the map' - 0 * mockForwardedSubscriptionEventCache.remove(_) - and: 'a response outcome has not been created' - 0 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(*_) - where: 'the following values are used' - scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist - 'Both model loader and notification are enabled' | true | true || 1 - 'Both model loader and notification are disabled' | false | false || 0 - 'Model loader enabled and notification disabled' | true | false || 1 - 'Model loader disabled and notification enabled' | false | true || 0 - } - - def getDmiOutEvent() { - def cmSubscriptionDmiOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') - return jsonObjectMapper.convertJsonString(cmSubscriptionDmiOutEventJsonData, CmSubscriptionDmiOutEvent.class) - } - - def getCloudEvent() { - return CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(getDmiOutEvent())) - .withId('some-id') - .withType('subscriptionCreated') - .withSource(URI.create('NCMP')).build() - } - - def getDmiOutConsumerRecord() { - return new ConsumerRecord('topic-name', 0, 0, 'event-key', getCloudEvent()) - } - - def getDataNode() { - def leaves = [status:'ACCEPTED', cmHandleId:'cmhandle1'] as Map - return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves(leaves).build() - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy deleted file mode 100644 index b13a2ceba..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.events.cmsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus -import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec extends Specification { - - CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map dmi out event to yang model subscription event'() { - given: 'a dmi out event' - def jsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') - def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionDmiOutEvent.class) - when: 'the event is mapped to a yang model subscription' - def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) - then: 'the resulting yang model subscription event contains the correct clientId' - assert result.clientId == "SCO-9989752" - and: 'subscription name' - assert result.subscriptionName == "cm-subscription-001" - and: 'predicate targets cm handle size as expected' - assert result.predicates.targetCmHandles.size() == 2 - and: 'predicate targets cm handle ids as expected' - assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2"] - and: 'the status for these targets is set to expected values' - assert result.predicates.targetCmHandles.status == [SubscriptionStatus.REJECTED, SubscriptionStatus.REJECTED] - } - -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy deleted file mode 100644 index 07b0925dc..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy +++ /dev/null @@ -1,89 +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.cmsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.models.CmSubscriptionEvent -import org.onap.cps.ncmp.api.models.CmSubscriptionStatus -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.spi.exceptions.DataValidationException -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec extends Specification { - - CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map cm subscription event to ncmp out event'() { - given: 'a cm subscription event' - def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') - def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) - when: 'cm subscription event is mapped to ncmp out event' - def result = objectUnderTest.toCmSubscriptionNcmpOutEvent(cmSubscriptionEvent) - then: 'the resulting ncmp out event contains expected pending targets per details grouping' - def pendingCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getPending() - assert pendingCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error happened' - assert pendingCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle4','CMHandle5'] - assert pendingCmHandleTargetsPerDetails.get(1).getDetails() == 'Some error causes pending' - assert pendingCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle3'] - and: 'the resulting ncmp out event contains expected rejected targets per details grouping' - def rejectedCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getRejected() - assert rejectedCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error message from the DMI' - assert rejectedCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle2'] - assert rejectedCmHandleTargetsPerDetails.get(1).getDetails() == 'Some error message from the DMI' - assert rejectedCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle1'] - } - - def 'Map cm subscription event to ncmp out event with the given scenarios causes an exception'() { - given: 'a cm subscription event' - def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') - def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) - and: 'set cm subscription status with given scenarios' - cmSubscriptionEvent.setCmSubscriptionStatus(subscriptionStatusList) - when: 'cm subscription event is mapped to ncmp out event' - objectUnderTest.toCmSubscriptionNcmpOutEvent(cmSubscriptionEvent) - then: 'a DataValidationException is thrown with an expected exception details' - def exception = thrown(DataValidationException) - exception.details == 'CmSubscriptionStatus list cannot be null or empty' - where: 'the following values are used' - scenario || subscriptionStatusList - 'A null subscription status list' || null - 'An empty subscription status list' || new ArrayList() - } - - def 'Map cm subscription event to ncmp out event without any exception'() { - given: 'a cm subscription Event' - def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') - def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionEvent.class) - when: 'cm subscription event is mapped to ncmp out event' - objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent) - then: 'no exception thrown' - noExceptionThrown() - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy deleted file mode 100644 index 31e883958..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy +++ /dev/null @@ -1,106 +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.cmsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import io.cloudevents.CloudEvent -import io.cloudevents.core.builder.CloudEventBuilder -import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class CmSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpec { - - def mockCmSubscriptionNcmpInEventForwarder = Mock(CmSubscriptionNcmpInEventForwarder) - def mockCmSubscriptionNcmpInEventMapper = Mock(CmSubscriptionNcmpInEventMapper) - def mockSubscriptionPersistence = Mock(SubscriptionPersistence) - def objectUnderTest = new CmSubscriptionNcmpInEventConsumer(mockCmSubscriptionNcmpInEventForwarder, mockCmSubscriptionNcmpInEventMapper, mockSubscriptionPersistence) - - def yangModelSubscriptionEvent = new YangModelSubscriptionEvent() - - @Autowired - JsonObjectMapper jsonObjectMapper - - @Autowired - ObjectMapper objectMapper - - - def 'Consume, persist and forward valid CM create message'() { - given: 'an event with data category CM' - def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) - testEventSent.getData().getDataType().setDataCategory(dataCategory) - def testCloudEventSent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(testEventSent)) - .withId('subscriptionCreated') - .withType(dataType) - .withSource(URI.create('some-resource')) - .withExtension('correlationid', 'test-cmhandle1').build() - def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) - and: 'notifications are enabled' - objectUnderTest.notificationFeatureEnabled = isNotificationEnabled - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = isModelLoaderEnabled - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(consumerRecord) - then: 'the event is mapped to a yangModelSubscription' - numberOfTimesToPersist * mockCmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent - and: 'the event is persisted' - numberOfTimesToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) - and: 'the event is forwarded' - numberOfTimesToForward * mockCmSubscriptionNcmpInEventForwarder.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreated') - where: 'given values are used' - scenario | dataCategory | dataType | isNotificationEnabled | isModelLoaderEnabled || numberOfTimesToForward || numberOfTimesToPersist - 'Both model loader and notification are enabled' | 'CM' | 'subscriptionCreated' | true | true || 1 || 1 - 'Both model loader and notification are disabled' | 'CM' | 'subscriptionCreated' | false | false || 0 || 0 - 'Model loader enabled and notification disabled' | 'CM' | 'subscriptionCreated' | false | true || 0 || 1 - 'Model loader disabled and notification enabled' | 'CM' | 'subscriptionCreated' | true | false || 1 || 0 - 'Flags are enabled but data category is FM' | 'FM' | 'subscriptionCreated' | true | true || 0 || 0 - 'Flags are enabled but data type is UPDATE' | 'CM' | 'subscriptionUpdated' | true | true || 0 || 1 - } - - def 'Consume event with wrong datastore causes an exception'() { - given: 'an event' - def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) - and: 'datastore is set to a passthrough-running datastore' - testEventSent.getData().getPredicates().setDatastore('operational') - def testCloudEventSent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(testEventSent)) - .withId('some-event-id') - .withType('some-event-type') - .withSource(URI.create('some-resource')) - .withExtension('correlationid', 'test-cmhandle1').build() - def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEvent(consumerRecord) - then: 'an operation not supported exception is thrown' - thrown(UnsupportedOperationException) - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy deleted file mode 100644 index ce117eef5..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy +++ /dev/null @@ -1,209 +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.cmsubscription - -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent - -import com.fasterxml.jackson.databind.ObjectMapper -import com.hazelcast.map.IMap -import io.cloudevents.CloudEvent -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus -import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent.TargetCmHandle -import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.spockframework.spring.SpringBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.util.concurrent.BlockingVariable -import java.util.concurrent.TimeUnit - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionNcmpInEventForwarder]) -class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec { - - @Autowired - CmSubscriptionNcmpInEventForwarder objectUnderTest - @SpringBean - InventoryPersistence mockInventoryPersistence = Mock(InventoryPersistence) - @SpringBean - EventsPublisher mockSubscriptionEventPublisher = Mock(EventsPublisher) - @SpringBean - IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) - @SpringBean - CmSubscriptionEventCloudMapper subscriptionEventCloudMapper = new CmSubscriptionEventCloudMapper(new ObjectMapper()) - @SpringBean - CmSubscriptionNcmpOutEventPublisher mockCmSubscriptionNcmpOutEventPublisher = Mock(CmSubscriptionNcmpOutEventPublisher) - @SpringBean - SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) - @SpringBean - CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper = Mappers.getMapper(CmSubscriptionNcmpInEventMapper) - @SpringBean - CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper = Mappers.getMapper(CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper) - @Autowired - JsonObjectMapper jsonObjectMapper - @Autowired - ObjectMapper objectMapper - - def 'Forward valid CM create subscription and simulate timeout'() { - given: 'a ncmp in event' - def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') - def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class) - and: 'the InventoryPersistence returns private properties for the supplied CM Handles' - 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [ - createYangModelCmHandleWithDmiProperty(1, 1,"shape","circle"), - createYangModelCmHandleWithDmiProperty(2, 1,"shape","square"), - createYangModelCmHandleWithDmiProperty(3, 2,"shape","triangle") - ] - and: 'the thread creation delay is reduced to 2 seconds for testing' - objectUnderTest.dmiResponseTimeoutInMs = 2000 - and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' - def block = new BlockingVariable(5) - when: 'the valid event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'subscriptionCreated') - then: 'An asynchronous call is made to the blocking variable' - block.get() - then: 'the event is added to the forwarded subscription event cache' - 1 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1","DMIName2"] as Set, 600, TimeUnit.SECONDS) - and: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' - 1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", - cloudEvent -> { - def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() - def cmHandle2 = createCmHandle('CMHandle2', ['shape': 'square'] as Map) - def cmHandle1 = createCmHandle('CMHandle1', ['shape': 'circle'] as Map) - targets == [cmHandle2, cmHandle1] - } - ) - 1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", - cloudEvent -> { - def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() - def cmHandle3 = createCmHandle('CMHandle3', ['shape':'triangle'] as Map) - targets == [cmHandle3] - } - ) - and: 'a separate thread has been created where the map is polled' - 1 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true - 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(*_) - and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' - 1 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> { block.set(_) } - } - - def 'Forward CM create subscription where target CM Handles are #scenario'() { - given: 'a ncmp in event' - def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') - def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class) - and: 'the target CMHandles are set to #scenario' - ncmpInEventJson.getData().getPredicates().setTargets(invalidTargets) - when: 'the event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'some-event-type') - then: 'an operation not supported exception is thrown' - thrown(UnsupportedOperationException) - where: - scenario | invalidTargets - 'null' | null - 'empty' | [] - 'wildcard' | ['CMHandle*'] - } - - def 'Forward valid CM create subscription where targets are not associated to any existing CMHandles'() { - given: 'a ncmp in event' - def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') - def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class) - and: 'the InventoryPersistence returns no private properties for the supplied CM Handles' - 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [] - and: 'some rejected cm handles' - def rejectedCmHandles = [new TargetCmHandle('CMHandle1', SubscriptionStatus.REJECTED, 'Cm handle does not exist'), - new TargetCmHandle('CMHandle2', SubscriptionStatus.REJECTED, 'Cm handle does not exist'), - new TargetCmHandle('CMHandle3', SubscriptionStatus.REJECTED, 'Cm handle does not exist')] - and: 'a yang model subscription event will be saved into the db with rejected cm handles' - def yangModelSubscriptionEvent = cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(ncmpInEventJson) - yangModelSubscriptionEvent.getPredicates().setTargetCmHandles(rejectedCmHandles) - and: 'the thread creation delay is reduced to 2 seconds for testing' - objectUnderTest.dmiResponseTimeoutInMs = 2000 - and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' - def block = new BlockingVariable(5) - when: 'the valid event is forwarded' - objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'subscriptionCreatedStatus') - then: 'the event is not added to the forwarded subscription event cache' - 0 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1", "DMIName2"] as Set) - and: 'the event is not being forwarded with the CMHandle private properties and does not provides a valid listenable future' - 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", - cloudEvent -> { - def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() - def cmHandle2 = createCmHandle('CMHandle2', ['shape': 'square'] as Map) - def cmHandle1 = createCmHandle('CMHandle1', ['shape': 'circle'] as Map) - targets == [cmHandle2, cmHandle1] - } - ) - 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", - cloudEvent -> { - def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() - def cmHandle3 = createCmHandle('CMHandle3', ['shape': 'triangle'] as Map) - targets == [cmHandle3] - } - ) - and: 'a separate thread has been created where the map is polled' - 0 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true - 0 * mockForwardedSubscriptionEventCache.get(_) - and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' - 0 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)} - and: 'the persistence service save target cm handles of the yang model subscription event as rejected' - 1 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) - and: 'subscription outcome has been sent' - 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(_, 'subscriptionCreatedStatus') - } - - def 'Extract domain name from URL for #scenario'() { - when: 'a valid dmi name is provided' - def domainName = objectUnderTest.toValidTopicSuffix(dmiName) - then: 'domain name is as expected with no port information' - assert domainName == expectedDomainName - where: '' - scenario | dmiName || expectedDomainName - 'insecure http url with port' | 'http://www.onap-dmi:8080/xyz=123' || 'onap-dmi' - 'insecure http url without port' | 'http://www.onap-dmi/xyz=123' || 'onap-dmi' - 'secure https url with port' | 'https://127.0.0.1:8080/xyz=123' || '127.0.0.1' - 'secure https url without port' | 'https://127.0.0.1/xyz=123' || '127.0.0.1' - 'servername without protocol and port' | 'dminame1' || 'dminame1' - 'servername without protocol' | 'www.onap-dmi:8080/xyz=123' || 'www.onap-dmi:8080/xyz=123' - - } - - static def createYangModelCmHandleWithDmiProperty(id, dmiId, propertyName, propertyValue) { - return new YangModelCmHandle(id: "CMHandle" + id, dmiDataServiceName: "DMIName" + dmiId, dmiProperties: [new YangModelCmHandle.Property(propertyName, propertyValue)]) - } - - static def createCmHandle(id, additionalProperties) { - def cmHandle = new CmHandle(); - cmHandle.setId(id) - cmHandle.setAdditionalProperties(additionalProperties) - return cmHandle - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy deleted file mode 100644 index 3d034fcdc..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy +++ /dev/null @@ -1,78 +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.cmsubscription - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus -import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - - -@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) -class CmSubscriptionNcmpInEventMapperSpec extends Specification { - - CmSubscriptionNcmpInEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionNcmpInEventMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map subscription event to yang model subscription event where #scenario'() { - given: 'a Subscription Event' - def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') - def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) - when: 'the event is mapped to a yang model subscription' - def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) - then: 'the resulting yang model subscription event contains the correct clientId' - assert result.clientId == "SCO-9989752" - and: 'subscription name' - assert result.subscriptionName == "cm-subscription-001" - and: 'is tagged value is false' - assert !result.isTagged - and: 'predicate targets ' - assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2", "CMHandle3"] - and: 'the status for these targets is set to pending' - assert result.predicates.targetCmHandles.status == [SubscriptionStatus.PENDING, SubscriptionStatus.PENDING, SubscriptionStatus.PENDING] - and: 'the topic is null' - assert result.topic == null - } - - def 'Map empty subscription event to yang model subscription event'() { - given: 'a new Subscription Event with no data' - def testEventToMap = new CmSubscriptionNcmpInEvent() - when: 'the event is mapped to a yang model subscription' - def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) - then: 'the resulting yang model subscription event contains null clientId' - assert result.clientId == null - and: 'subscription name is null' - assert result.subscriptionName == null - and: 'is tagged value is false' - assert result.isTagged == false - and: 'predicates is null' - assert result.predicates == null - and: 'the topic is null' - assert result.topic == null - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy deleted file mode 100644 index a0567cb4c..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy +++ /dev/null @@ -1,128 +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.cmsubscription - -import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESSFULLY_APPLIED_SUBSCRIPTION -import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_PENDING -import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_NOT_APPLICABLE -import static org.onap.cps.ncmp.api.NcmpResponseStatus.PARTIALLY_APPLIED_SUBSCRIPTION - -import com.fasterxml.jackson.databind.ObjectMapper -import io.cloudevents.CloudEvent -import io.cloudevents.core.builder.CloudEventBuilder -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence -import org.onap.cps.ncmp.api.impl.utils.DataNodeBaseSpec -import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper -import org.onap.cps.ncmp.api.models.CmSubscriptionEvent -import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.spockframework.spring.SpringBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper, CmSubscriptionNcmpOutEventPublisher]) -class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec { - - @Autowired - CmSubscriptionNcmpOutEventPublisher objectUnderTest - - @SpringBean - SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) - @SpringBean - EventsPublisher mockCmSubscriptionNcmpOutEventPublisher = Mock(EventsPublisher) - @SpringBean - CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper = Mappers.getMapper(CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper) - @SpringBean - SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper = new SubscriptionOutcomeCloudMapper(new ObjectMapper()) - - @Autowired - JsonObjectMapper jsonObjectMapper - - @Autowired - ObjectMapper objectMapper - - def 'Send response to the client apps successfully'() { - given: 'a cm subscription event' - def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') - def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) - and: 'a ncmp out event' - def ncmpOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent2.json') - def ncmpOutEvent = jsonObjectMapper.convertJsonString(ncmpOutEventJsonData, CmSubscriptionNcmpOutEvent.class) - and: 'a random id for the cloud event' - SubscriptionOutcomeCloudMapper.randomId = 'some-id' - and: 'a cloud event containing the outcome event' - def testCloudEventSent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(ncmpOutEvent)) - .withId('some-id') - .withType('subscriptionCreatedStatus') - .withDataSchema(URI.create('urn:cps:' + 'org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent' + ':1.0.0')) - .withExtension("correlationid", 'SCO-9989752cm-subscription-001') - .withSource(URI.create('NCMP')).build() - and: 'the persistence service return a data node that includes pending cm handles that makes it partial success' - mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [dataNode4] - when: 'the response is being sent' - objectUnderTest.sendResponse(cmSubscriptionEvent, 'subscriptionCreatedStatus') - then: 'the publisher publish the cloud event with itself and expected parameters' - 1 * mockCmSubscriptionNcmpOutEventPublisher.publishCloudEvent('subscription-response', 'SCO-9989752cm-subscription-001', testCloudEventSent) - } - - def 'Create ncmp out message as expected'() { - given: 'a cm subscription event' - def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') - def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) - and: 'a ncmp out event' - def ncmpOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent.json') - def ncmpOutEvent = jsonObjectMapper.convertJsonString(ncmpOutEventJsonData, CmSubscriptionNcmpOutEvent.class) - and: 'a status code and status message a per #scenarios' - ncmpOutEvent.getData().setStatusCode(statusCode) - ncmpOutEvent.getData().setStatusMessage(statusMessage) - when: 'a cm subscription event is being formed' - def expectedResult = objectUnderTest.fromCmSubscriptionEvent(cmSubscriptionEvent, ncmpEventResponseCode) - then: 'the result will be equal to ncmp out event' - expectedResult == ncmpOutEvent - where: 'the following values are used' - scenario | ncmpEventResponseCode || statusMessage || statusCode - 'is full outcome' | SUCCESSFULLY_APPLIED_SUBSCRIPTION || 'successfully applied subscription' || 1 - 'is partial outcome' | PARTIALLY_APPLIED_SUBSCRIPTION || 'partially applied subscription' || 104 - } - - def 'Check cm handle id to status map to see if it is a full outcome response'() { - when: 'is full outcome response evaluated' - def response = objectUnderTest.decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap) - then: 'the result will be as expected' - response == expectedOutcomeResponseDecision - where: 'the following values are used' - scenario | cmHandleIdToStatusAndDetailsAsMap || expectedOutcomeResponseDecision - 'The map contains PENDING status' | [CMHandle1: [details: 'Subscription forwarded to dmi plugin', status: 'PENDING'] as Map] as Map || SUBSCRIPTION_PENDING - 'The map contains ACCEPTED status' | [CMHandle1: [details: '', status: 'ACCEPTED'] as Map] as Map || SUCCESSFULLY_APPLIED_SUBSCRIPTION - 'The map contains REJECTED status' | [CMHandle1: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map] as Map || SUBSCRIPTION_NOT_APPLICABLE - 'The map contains PENDING and PENDING statuses' | [CMHandle1: [details: 'Some details', status: 'PENDING'] as Map, CMHandle2: [details: 'Some details', status: 'PENDING'] as Map as Map] as Map || SUBSCRIPTION_PENDING - 'The map contains ACCEPTED and ACCEPTED statuses' | [CMHandle1: [details: '', status: 'ACCEPTED'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map || SUCCESSFULLY_APPLIED_SUBSCRIPTION - 'The map contains REJECTED and REJECTED statuses' | [CMHandle1: [details: 'Reject details', status: 'REJECTED'] as Map, CMHandle2: [details: 'Reject details', status: 'REJECTED'] as Map as Map] as Map || SUBSCRIPTION_NOT_APPLICABLE - 'The map contains PENDING and ACCEPTED statuses' | [CMHandle1: [details: 'Some details', status: 'PENDING'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map || PARTIALLY_APPLIED_SUBSCRIPTION - 'The map contains REJECTED and ACCEPTED statuses' | [CMHandle1: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map || PARTIALLY_APPLIED_SUBSCRIPTION - 'The map contains PENDING and REJECTED statuses' | [CMHandle1: [details: 'Subscription forwarded to dmi plugin', status: 'PENDING'] as Map, CMHandle2: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map as Map] as Map || PARTIALLY_APPLIED_SUBSCRIPTION - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy new file mode 100644 index 000000000..1427bf9ba --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/ClientCmSubscriptionNcmpInEventMapperSpec.groovy @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class ClientCmSubscriptionNcmpInEventMapperSpec extends Specification { + + CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map clients subscription event to ncmps subscription event'() { + given: 'a Subscription Event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + when: 'the client event is mapped to a ncmp subscription event' + def result = objectUnderTest.toCmSubscriptionDmiInEvent(testEventToMap) + then: 'the resulting ncmp subscription event contains the correct clientId' + assert result.getData().getSubscription().getClientID() == "SCO-9989752" + and: 'subscription name' + assert result.getData().getSubscription().getName() == "cm-subscription-001" + and: 'is tagged value is false' + assert result.getData().getSubscription().getIsTagged() == false + and: 'data category is CM' + assert result.getData().getDataType().getDataCategory() == 'CM' + and: 'predicate targets is null' + assert result.getData().getPredicates().getTargets() == [] + and: 'datastore is passthrough-running' + assert result.getData().getPredicates().getDatastore() == 'ncmp-datastore:passthrough-running' + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy new file mode 100644 index 000000000..5d4f5f97e --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy @@ -0,0 +1,140 @@ +/* + * ============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.deprecated.cmsubscription + +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME + +import com.fasterxml.jackson.databind.ObjectMapper +import com.hazelcast.map.IMap +import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder +import org.apache.kafka.clients.consumer.ConsumerRecord +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistenceImpl +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.spi.model.DataNodeBuilder +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec { + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) + def mockSubscriptionPersistence = Mock(SubscriptionPersistenceImpl) + def mockSubscriptionEventResponseMapper = Mock(CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper) + def mockCmSubscriptionNcmpOutEventPublisher = Mock(CmSubscriptionNcmpOutEventPublisher) + + def objectUnderTest = new CmSubscriptionDmiOutEventConsumer(mockForwardedSubscriptionEventCache, + mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockCmSubscriptionNcmpOutEventPublisher) + + def 'Consume dmi out event where all DMIs have responded'() { + given: 'a consumer record including cloud event having dmi out event' + def dmiOutConsumerRecord = getDmiOutConsumerRecord() + and: 'notifications are enabled' + objectUnderTest.notificationFeatureEnabled = notificationEnabled + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled + and: 'subscription persistence service returns data node includes no pending cm handle' + mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [getDataNode()] + when: 'the valid event is consumed' + objectUnderTest.consumeDmiOutEvent(dmiOutConsumerRecord) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['some-dmi-name'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> ([] as Set) + and: 'the response event is map to yang model' + numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) + and: 'the response event is persisted into the db' + numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) + and: 'the subscription event is removed from the map' + numberOfTimeToRemove * mockForwardedSubscriptionEventCache.remove('SCO-9989752cm-subscription-001') + and: 'a response outcome has been created' + numberOfTimeToResponse * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(_, 'subscriptionCreated') + where: 'the following values are used' + scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist || numberOfTimeToRemove || numberOfTimeToResponse + 'Both model loader and notification are enabled' | true | true || 1 || 1 || 1 + 'Both model loader and notification are disabled' | false | false || 0 || 0 || 0 + 'Model loader enabled and notification disabled' | true | false || 1 || 0 || 0 + 'Model loader disabled and notification enabled' | false | true || 0 || 1 || 1 + } + + def 'Consume dmi out event where another DMI has not yet responded'() { + given: 'a subscription event response and notifications are enabled' + objectUnderTest.notificationFeatureEnabled = notificationEnabled + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled + when: 'the valid event is consumed' + objectUnderTest.consumeDmiOutEvent(getDmiOutConsumerRecord()) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['responded-dmi', 'non-responded-dmi'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['non-responded-dmi'] as Set) + and: 'the response event is map to yang model' + numberOfTimeToPersist * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) + and: 'the response event is persisted into the db' + numberOfTimeToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(_) + and: 'the subscription event is removed from the map' + and: 'the subscription event is not removed from the map' + 0 * mockForwardedSubscriptionEventCache.remove(_) + and: 'a response outcome has not been created' + 0 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(*_) + where: 'the following values are used' + scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist + 'Both model loader and notification are enabled' | true | true || 1 + 'Both model loader and notification are disabled' | false | false || 0 + 'Model loader enabled and notification disabled' | true | false || 1 + 'Model loader disabled and notification enabled' | false | true || 0 + } + + def getDmiOutEvent() { + def cmSubscriptionDmiOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + return jsonObjectMapper.convertJsonString(cmSubscriptionDmiOutEventJsonData, CmSubscriptionDmiOutEvent.class) + } + + def getCloudEvent() { + return CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(getDmiOutEvent())) + .withId('some-id') + .withType('subscriptionCreated') + .withSource(URI.create('NCMP')).build() + } + + def getDmiOutConsumerRecord() { + return new ConsumerRecord('topic-name', 0, 0, 'event-key', getCloudEvent()) + } + + def getDataNode() { + def leaves = [status:'ACCEPTED', cmHandleId:'cmhandle1'] as Map + return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) + .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') + .withLeaves(leaves).build() + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy new file mode 100644 index 000000000..519d8e2e0 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus +import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec extends Specification { + + CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map dmi out event to yang model subscription event'() { + given: 'a dmi out event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json') + def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionDmiOutEvent.class) + when: 'the event is mapped to a yang model subscription' + def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) + then: 'the resulting yang model subscription event contains the correct clientId' + assert result.clientId == "SCO-9989752" + and: 'subscription name' + assert result.subscriptionName == "cm-subscription-001" + and: 'predicate targets cm handle size as expected' + assert result.predicates.targetCmHandles.size() == 2 + and: 'predicate targets cm handle ids as expected' + assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2"] + and: 'the status for these targets is set to expected values' + assert result.predicates.targetCmHandles.status == [SubscriptionStatus.REJECTED, SubscriptionStatus.REJECTED] + } + +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy new file mode 100644 index 000000000..891940a41 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy @@ -0,0 +1,89 @@ +/* + * ============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.deprecated.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.models.CmSubscriptionEvent +import org.onap.cps.ncmp.api.models.CmSubscriptionStatus +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.spi.exceptions.DataValidationException +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec extends Specification { + + CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map cm subscription event to ncmp out event'() { + given: 'a cm subscription event' + def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') + def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) + when: 'cm subscription event is mapped to ncmp out event' + def result = objectUnderTest.toCmSubscriptionNcmpOutEvent(cmSubscriptionEvent) + then: 'the resulting ncmp out event contains expected pending targets per details grouping' + def pendingCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getPending() + assert pendingCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error happened' + assert pendingCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle4','CMHandle5'] + assert pendingCmHandleTargetsPerDetails.get(1).getDetails() == 'Some error causes pending' + assert pendingCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle3'] + and: 'the resulting ncmp out event contains expected rejected targets per details grouping' + def rejectedCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getRejected() + assert rejectedCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error message from the DMI' + assert rejectedCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle2'] + assert rejectedCmHandleTargetsPerDetails.get(1).getDetails() == 'Some error message from the DMI' + assert rejectedCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle1'] + } + + def 'Map cm subscription event to ncmp out event with the given scenarios causes an exception'() { + given: 'a cm subscription event' + def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') + def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) + and: 'set cm subscription status with given scenarios' + cmSubscriptionEvent.setCmSubscriptionStatus(subscriptionStatusList) + when: 'cm subscription event is mapped to ncmp out event' + objectUnderTest.toCmSubscriptionNcmpOutEvent(cmSubscriptionEvent) + then: 'a DataValidationException is thrown with an expected exception details' + def exception = thrown(DataValidationException) + exception.details == 'CmSubscriptionStatus list cannot be null or empty' + where: 'the following values are used' + scenario || subscriptionStatusList + 'A null subscription status list' || null + 'An empty subscription status list' || new ArrayList() + } + + def 'Map cm subscription event to ncmp out event without any exception'() { + given: 'a cm subscription Event' + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') + def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionEvent.class) + when: 'cm subscription event is mapped to ncmp out event' + objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent) + then: 'no exception thrown' + noExceptionThrown() + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy new file mode 100644 index 000000000..d708bd658 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventConsumerSpec.groovy @@ -0,0 +1,106 @@ +/* + * ============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.deprecated.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder +import org.apache.kafka.clients.consumer.ConsumerRecord +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistence +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class CmSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpec { + + def mockCmSubscriptionNcmpInEventForwarder = Mock(CmSubscriptionNcmpInEventForwarder) + def mockCmSubscriptionNcmpInEventMapper = Mock(CmSubscriptionNcmpInEventMapper) + def mockSubscriptionPersistence = Mock(SubscriptionPersistence) + def objectUnderTest = new CmSubscriptionNcmpInEventConsumer(mockCmSubscriptionNcmpInEventForwarder, mockCmSubscriptionNcmpInEventMapper, mockSubscriptionPersistence) + + def yangModelSubscriptionEvent = new YangModelSubscriptionEvent() + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + + def 'Consume, persist and forward valid CM create message'() { + given: 'an event with data category CM' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + testEventSent.getData().getDataType().setDataCategory(dataCategory) + def testCloudEventSent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(testEventSent)) + .withId('subscriptionCreated') + .withType(dataType) + .withSource(URI.create('some-resource')) + .withExtension('correlationid', 'test-cmhandle1').build() + def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) + and: 'notifications are enabled' + objectUnderTest.notificationFeatureEnabled = isNotificationEnabled + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = isModelLoaderEnabled + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(consumerRecord) + then: 'the event is mapped to a yangModelSubscription' + numberOfTimesToPersist * mockCmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(testEventSent) >> yangModelSubscriptionEvent + and: 'the event is persisted' + numberOfTimesToPersist * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) + and: 'the event is forwarded' + numberOfTimesToForward * mockCmSubscriptionNcmpInEventForwarder.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreated') + where: 'given values are used' + scenario | dataCategory | dataType | isNotificationEnabled | isModelLoaderEnabled || numberOfTimesToForward || numberOfTimesToPersist + 'Both model loader and notification are enabled' | 'CM' | 'subscriptionCreated' | true | true || 1 || 1 + 'Both model loader and notification are disabled' | 'CM' | 'subscriptionCreated' | false | false || 0 || 0 + 'Model loader enabled and notification disabled' | 'CM' | 'subscriptionCreated' | false | true || 0 || 1 + 'Model loader disabled and notification enabled' | 'CM' | 'subscriptionCreated' | true | false || 1 || 0 + 'Flags are enabled but data category is FM' | 'FM' | 'subscriptionCreated' | true | true || 0 || 0 + 'Flags are enabled but data type is UPDATE' | 'CM' | 'subscriptionUpdated' | true | true || 0 || 1 + } + + def 'Consume event with wrong datastore causes an exception'() { + given: 'an event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + and: 'datastore is set to a passthrough-running datastore' + testEventSent.getData().getPredicates().setDatastore('operational') + def testCloudEventSent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(testEventSent)) + .withId('some-event-id') + .withType('some-event-type') + .withSource(URI.create('some-resource')) + .withExtension('correlationid', 'test-cmhandle1').build() + def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testCloudEventSent) + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEvent(consumerRecord) + then: 'an operation not supported exception is thrown' + thrown(UnsupportedOperationException) + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy new file mode 100644 index 000000000..4a66473ec --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy @@ -0,0 +1,209 @@ +/* + * ============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.deprecated.cmsubscription + +import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent + +import com.fasterxml.jackson.databind.ObjectMapper +import com.hazelcast.map.IMap +import io.cloudevents.CloudEvent +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistence +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus +import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent.TargetCmHandle +import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.util.concurrent.BlockingVariable +import java.util.concurrent.TimeUnit + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionNcmpInEventForwarder]) +class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec { + + @Autowired + CmSubscriptionNcmpInEventForwarder objectUnderTest + @SpringBean + InventoryPersistence mockInventoryPersistence = Mock(InventoryPersistence) + @SpringBean + EventsPublisher mockSubscriptionEventPublisher = Mock(EventsPublisher) + @SpringBean + IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) + @SpringBean + CmSubscriptionEventCloudMapper subscriptionEventCloudMapper = new CmSubscriptionEventCloudMapper(new ObjectMapper()) + @SpringBean + CmSubscriptionNcmpOutEventPublisher mockCmSubscriptionNcmpOutEventPublisher = Mock(CmSubscriptionNcmpOutEventPublisher) + @SpringBean + SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) + @SpringBean + CmSubscriptionNcmpInEventMapper cmSubscriptionNcmpInEventMapper = Mappers.getMapper(CmSubscriptionNcmpInEventMapper) + @SpringBean + CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper = Mappers.getMapper(CmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper) + @Autowired + JsonObjectMapper jsonObjectMapper + @Autowired + ObjectMapper objectMapper + + def 'Forward valid CM create subscription and simulate timeout'() { + given: 'a ncmp in event' + def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class) + and: 'the InventoryPersistence returns private properties for the supplied CM Handles' + 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [ + createYangModelCmHandleWithDmiProperty(1, 1,"shape","circle"), + createYangModelCmHandleWithDmiProperty(2, 1,"shape","square"), + createYangModelCmHandleWithDmiProperty(3, 2,"shape","triangle") + ] + and: 'the thread creation delay is reduced to 2 seconds for testing' + objectUnderTest.dmiResponseTimeoutInMs = 2000 + and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' + def block = new BlockingVariable(5) + when: 'the valid event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'subscriptionCreated') + then: 'An asynchronous call is made to the blocking variable' + block.get() + then: 'the event is added to the forwarded subscription event cache' + 1 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1","DMIName2"] as Set, 600, TimeUnit.SECONDS) + and: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' + 1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", + cloudEvent -> { + def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() + def cmHandle2 = createCmHandle('CMHandle2', ['shape': 'square'] as Map) + def cmHandle1 = createCmHandle('CMHandle1', ['shape': 'circle'] as Map) + targets == [cmHandle2, cmHandle1] + } + ) + 1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", + cloudEvent -> { + def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() + def cmHandle3 = createCmHandle('CMHandle3', ['shape':'triangle'] as Map) + targets == [cmHandle3] + } + ) + and: 'a separate thread has been created where the map is polled' + 1 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true + 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(*_) + and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' + 1 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> { block.set(_) } + } + + def 'Forward CM create subscription where target CM Handles are #scenario'() { + given: 'a ncmp in event' + def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class) + and: 'the target CMHandles are set to #scenario' + ncmpInEventJson.getData().getPredicates().setTargets(invalidTargets) + when: 'the event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'some-event-type') + then: 'an operation not supported exception is thrown' + thrown(UnsupportedOperationException) + where: + scenario | invalidTargets + 'null' | null + 'empty' | [] + 'wildcard' | ['CMHandle*'] + } + + def 'Forward valid CM create subscription where targets are not associated to any existing CMHandles'() { + given: 'a ncmp in event' + def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class) + and: 'the InventoryPersistence returns no private properties for the supplied CM Handles' + 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [] + and: 'some rejected cm handles' + def rejectedCmHandles = [new TargetCmHandle('CMHandle1', SubscriptionStatus.REJECTED, 'Cm handle does not exist'), + new TargetCmHandle('CMHandle2', SubscriptionStatus.REJECTED, 'Cm handle does not exist'), + new TargetCmHandle('CMHandle3', SubscriptionStatus.REJECTED, 'Cm handle does not exist')] + and: 'a yang model subscription event will be saved into the db with rejected cm handles' + def yangModelSubscriptionEvent = cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(ncmpInEventJson) + yangModelSubscriptionEvent.getPredicates().setTargetCmHandles(rejectedCmHandles) + and: 'the thread creation delay is reduced to 2 seconds for testing' + objectUnderTest.dmiResponseTimeoutInMs = 2000 + and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' + def block = new BlockingVariable(5) + when: 'the valid event is forwarded' + objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'subscriptionCreatedStatus') + then: 'the event is not added to the forwarded subscription event cache' + 0 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1", "DMIName2"] as Set) + and: 'the event is not being forwarded with the CMHandle private properties and does not provides a valid listenable future' + 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", + cloudEvent -> { + def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() + def cmHandle2 = createCmHandle('CMHandle2', ['shape': 'square'] as Map) + def cmHandle1 = createCmHandle('CMHandle1', ['shape': 'circle'] as Map) + targets == [cmHandle2, cmHandle1] + } + ) + 0 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", + cloudEvent -> { + def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets() + def cmHandle3 = createCmHandle('CMHandle3', ['shape': 'triangle'] as Map) + targets == [cmHandle3] + } + ) + and: 'a separate thread has been created where the map is polled' + 0 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true + 0 * mockForwardedSubscriptionEventCache.get(_) + and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' + 0 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)} + and: 'the persistence service save target cm handles of the yang model subscription event as rejected' + 1 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent) + and: 'subscription outcome has been sent' + 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(_, 'subscriptionCreatedStatus') + } + + def 'Extract domain name from URL for #scenario'() { + when: 'a valid dmi name is provided' + def domainName = objectUnderTest.toValidTopicSuffix(dmiName) + then: 'domain name is as expected with no port information' + assert domainName == expectedDomainName + where: '' + scenario | dmiName || expectedDomainName + 'insecure http url with port' | 'http://www.onap-dmi:8080/xyz=123' || 'onap-dmi' + 'insecure http url without port' | 'http://www.onap-dmi/xyz=123' || 'onap-dmi' + 'secure https url with port' | 'https://127.0.0.1:8080/xyz=123' || '127.0.0.1' + 'secure https url without port' | 'https://127.0.0.1/xyz=123' || '127.0.0.1' + 'servername without protocol and port' | 'dminame1' || 'dminame1' + 'servername without protocol' | 'www.onap-dmi:8080/xyz=123' || 'www.onap-dmi:8080/xyz=123' + + } + + static def createYangModelCmHandleWithDmiProperty(id, dmiId, propertyName, propertyValue) { + return new YangModelCmHandle(id: "CMHandle" + id, dmiDataServiceName: "DMIName" + dmiId, dmiProperties: [new YangModelCmHandle.Property(propertyName, propertyValue)]) + } + + static def createCmHandle(id, additionalProperties) { + def cmHandle = new CmHandle(); + cmHandle.setId(id) + cmHandle.setAdditionalProperties(additionalProperties) + return cmHandle + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy new file mode 100644 index 000000000..f28e614cc --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpInEventMapperSpec.groovy @@ -0,0 +1,78 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.deprecated.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionStatus +import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + + +@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper]) +class CmSubscriptionNcmpInEventMapperSpec extends Specification { + + CmSubscriptionNcmpInEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionNcmpInEventMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map subscription event to yang model subscription event where #scenario'() { + given: 'a Subscription Event' + def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json') + def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class) + when: 'the event is mapped to a yang model subscription' + def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) + then: 'the resulting yang model subscription event contains the correct clientId' + assert result.clientId == "SCO-9989752" + and: 'subscription name' + assert result.subscriptionName == "cm-subscription-001" + and: 'is tagged value is false' + assert !result.isTagged + and: 'predicate targets ' + assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2", "CMHandle3"] + and: 'the status for these targets is set to pending' + assert result.predicates.targetCmHandles.status == [SubscriptionStatus.PENDING, SubscriptionStatus.PENDING, SubscriptionStatus.PENDING] + and: 'the topic is null' + assert result.topic == null + } + + def 'Map empty subscription event to yang model subscription event'() { + given: 'a new Subscription Event with no data' + def testEventToMap = new CmSubscriptionNcmpInEvent() + when: 'the event is mapped to a yang model subscription' + def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) + then: 'the resulting yang model subscription event contains null clientId' + assert result.clientId == null + and: 'subscription name is null' + assert result.subscriptionName == null + and: 'is tagged value is false' + assert result.isTagged == false + and: 'predicates is null' + assert result.predicates == null + and: 'the topic is null' + assert result.topic == null + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy new file mode 100644 index 000000000..85f8776df --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/deprecated/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy @@ -0,0 +1,128 @@ +/* + * ============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.deprecated.cmsubscription + +import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESSFULLY_APPLIED_SUBSCRIPTION +import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_PENDING +import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_NOT_APPLICABLE +import static org.onap.cps.ncmp.api.NcmpResponseStatus.PARTIALLY_APPLIED_SUBSCRIPTION + +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.deprecated.subscriptions.SubscriptionPersistence +import org.onap.cps.ncmp.api.impl.utils.DataNodeBaseSpec +import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper +import org.onap.cps.ncmp.api.models.CmSubscriptionEvent +import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper, CmSubscriptionNcmpOutEventPublisher]) +class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec { + + @Autowired + CmSubscriptionNcmpOutEventPublisher objectUnderTest + + @SpringBean + SubscriptionPersistence mockSubscriptionPersistence = Mock(SubscriptionPersistence) + @SpringBean + EventsPublisher mockCmSubscriptionNcmpOutEventPublisher = Mock(EventsPublisher) + @SpringBean + CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper = Mappers.getMapper(CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper) + @SpringBean + SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper = new SubscriptionOutcomeCloudMapper(new ObjectMapper()) + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + def 'Send response to the client apps successfully'() { + given: 'a cm subscription event' + def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') + def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) + and: 'a ncmp out event' + def ncmpOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent2.json') + def ncmpOutEvent = jsonObjectMapper.convertJsonString(ncmpOutEventJsonData, CmSubscriptionNcmpOutEvent.class) + and: 'a random id for the cloud event' + SubscriptionOutcomeCloudMapper.randomId = 'some-id' + and: 'a cloud event containing the outcome event' + def testCloudEventSent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(ncmpOutEvent)) + .withId('some-id') + .withType('subscriptionCreatedStatus') + .withDataSchema(URI.create('urn:cps:' + 'org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent' + ':1.0.0')) + .withExtension("correlationid", 'SCO-9989752cm-subscription-001') + .withSource(URI.create('NCMP')).build() + and: 'the persistence service return a data node that includes pending cm handles that makes it partial success' + mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [dataNode4] + when: 'the response is being sent' + objectUnderTest.sendResponse(cmSubscriptionEvent, 'subscriptionCreatedStatus') + then: 'the publisher publish the cloud event with itself and expected parameters' + 1 * mockCmSubscriptionNcmpOutEventPublisher.publishCloudEvent('subscription-response', 'SCO-9989752cm-subscription-001', testCloudEventSent) + } + + def 'Create ncmp out message as expected'() { + given: 'a cm subscription event' + def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json') + def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class) + and: 'a ncmp out event' + def ncmpOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent.json') + def ncmpOutEvent = jsonObjectMapper.convertJsonString(ncmpOutEventJsonData, CmSubscriptionNcmpOutEvent.class) + and: 'a status code and status message a per #scenarios' + ncmpOutEvent.getData().setStatusCode(statusCode) + ncmpOutEvent.getData().setStatusMessage(statusMessage) + when: 'a cm subscription event is being formed' + def expectedResult = objectUnderTest.fromCmSubscriptionEvent(cmSubscriptionEvent, ncmpEventResponseCode) + then: 'the result will be equal to ncmp out event' + expectedResult == ncmpOutEvent + where: 'the following values are used' + scenario | ncmpEventResponseCode || statusMessage || statusCode + 'is full outcome' | SUCCESSFULLY_APPLIED_SUBSCRIPTION || 'successfully applied subscription' || 1 + 'is partial outcome' | PARTIALLY_APPLIED_SUBSCRIPTION || 'partially applied subscription' || 104 + } + + def 'Check cm handle id to status map to see if it is a full outcome response'() { + when: 'is full outcome response evaluated' + def response = objectUnderTest.decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap) + then: 'the result will be as expected' + response == expectedOutcomeResponseDecision + where: 'the following values are used' + scenario | cmHandleIdToStatusAndDetailsAsMap || expectedOutcomeResponseDecision + 'The map contains PENDING status' | [CMHandle1: [details: 'Subscription forwarded to dmi plugin', status: 'PENDING'] as Map] as Map || SUBSCRIPTION_PENDING + 'The map contains ACCEPTED status' | [CMHandle1: [details: '', status: 'ACCEPTED'] as Map] as Map || SUCCESSFULLY_APPLIED_SUBSCRIPTION + 'The map contains REJECTED status' | [CMHandle1: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map] as Map || SUBSCRIPTION_NOT_APPLICABLE + 'The map contains PENDING and PENDING statuses' | [CMHandle1: [details: 'Some details', status: 'PENDING'] as Map, CMHandle2: [details: 'Some details', status: 'PENDING'] as Map as Map] as Map || SUBSCRIPTION_PENDING + 'The map contains ACCEPTED and ACCEPTED statuses' | [CMHandle1: [details: '', status: 'ACCEPTED'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map || SUCCESSFULLY_APPLIED_SUBSCRIPTION + 'The map contains REJECTED and REJECTED statuses' | [CMHandle1: [details: 'Reject details', status: 'REJECTED'] as Map, CMHandle2: [details: 'Reject details', status: 'REJECTED'] as Map as Map] as Map || SUBSCRIPTION_NOT_APPLICABLE + 'The map contains PENDING and ACCEPTED statuses' | [CMHandle1: [details: 'Some details', status: 'PENDING'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map || PARTIALLY_APPLIED_SUBSCRIPTION + 'The map contains REJECTED and ACCEPTED statuses' | [CMHandle1: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map || PARTIALLY_APPLIED_SUBSCRIPTION + 'The map contains PENDING and REJECTED statuses' | [CMHandle1: [details: 'Subscription forwarded to dmi plugin', status: 'PENDING'] as Map, CMHandle2: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map as Map] as Map || PARTIALLY_APPLIED_SUBSCRIPTION + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceSpec.groovy deleted file mode 100644 index 541a4f7ba..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceSpec.groovy +++ /dev/null @@ -1,99 +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.subscriptions - -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.api.CpsDataService -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent -import org.onap.cps.spi.model.DataNodeBuilder -import org.onap.cps.utils.JsonObjectMapper -import org.onap.cps.api.CpsModuleService -import org.onap.cps.spi.utils.CpsValidator -import spock.lang.Specification - -class SubscriptionPersistenceSpec extends Specification { - - private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions"; - private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry"; - private static final String SUBSCRIPTION_REGISTRY_PREDICATES_XPATH = "/subscription-registry/subscription[@clientID='some-client-id' and @subscriptionName='some-subscription-name']/predicates"; - - def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) - def mockCpsDataService = Mock(CpsDataService) - def mockCpsModuleService = Mock(CpsModuleService) - def mockCpsValidator = Mock(CpsValidator) - - def objectUnderTest = new SubscriptionPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService, - mockCpsModuleService, mockCpsValidator) - - def predicates = new YangModelSubscriptionEvent.Predicates(datastore: 'some-datastore', - targetCmHandles: [new YangModelSubscriptionEvent.TargetCmHandle('cmhandle1'), - new YangModelSubscriptionEvent.TargetCmHandle('cmhandle2')]) - def yangModelSubscriptionEvent = new YangModelSubscriptionEvent(clientId: 'some-client-id', - subscriptionName: 'some-subscription-name', tagged: true, topic: 'some-topic', predicates: predicates) - - def 'save a subscription event as yang model into db for the #scenarios' () { - given: 'a blank data node that exist in db' - def blankDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry').build() - and: 'cps data service return an empty data node' - mockCpsDataService.getDataNodes(*_) >> [blankDataNode] - when: 'the yangModelSubscriptionEvent is saved into db' - objectUnderTest.saveSubscriptionEvent(yangModelSubscriptionEvent) - then: 'the cpsDataService save operation is called with the correct data' - 1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - SUBSCRIPTION_REGISTRY_PARENT, - '{"subscription":[{' + - '"topic":"some-topic",' + - '"predicates":{"datastore":"some-datastore","targetCmHandles":[{"cmHandleId":"cmhandle1","status":"PENDING","details":"Subscription forwarded to dmi plugin"},' + - '{"cmHandleId":"cmhandle2","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]},' + - '"clientID":"some-client-id","subscriptionName":"some-subscription-name","isTagged":true}]}', - NO_TIMESTAMP) - } - - def 'add or replace cm handle list element into db' () { - given: 'a data node with child node exist in db' - def leaves1 = [status:'REJECTED', cmHandleId:'cmhandle1', details:'Cm handle does not exist'] as Map - def childDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves(leaves1).build() - def engagedDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry') - .withChildDataNodes([childDataNode]).build() - and: 'cps data service return data node including a child data node' - mockCpsDataService.getDataNodes(*_) >> [engagedDataNode] - and: 'cps data service return data node for querying by xpaths' - mockCpsDataService.getDataNodesForMultipleXpaths(*_) >> [engagedDataNode] - when: 'the yang model subscription event is saved into db' - objectUnderTest.saveSubscriptionEvent(yangModelSubscriptionEvent) - then: 'the cpsDataService save non-existing cm handle with the correct data' - 1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - SUBSCRIPTION_REGISTRY_PREDICATES_XPATH, '{"targetCmHandles":[{"cmHandleId":"cmhandle2","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]}', - NO_TIMESTAMP) - and: 'the cpsDataService update existing cm handle with the correct data' - 1 * mockCpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - SUBSCRIPTION_REGISTRY_PREDICATES_XPATH, '{"targetCmHandles":[{"cmHandleId":"cmhandle1","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]}', - NO_TIMESTAMP) - } - -} -- cgit 1.2.3-korg