diff options
Diffstat (limited to 'cps-ncmp-service')
26 files changed, 552 insertions, 257 deletions
diff --git a/cps-ncmp-service/lombok.config b/cps-ncmp-service/lombok.config index 1fba85bb7b..6776ef0f51 100644 --- a/cps-ncmp-service/lombok.config +++ b/cps-ncmp-service/lombok.config @@ -18,3 +18,4 @@ config.stopBubbling = true lombok.addLombokGeneratedAnnotation = true +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml index 9beb6b7b0f..d6ea71b952 100644 --- a/cps-ncmp-service/pom.xml +++ b/cps-ncmp-service/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.4-SNAPSHOT</version> + <version>3.4.5-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java index b9c834c559..462679e74f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,8 @@ public enum NcmpResponseStatus { SUBSCRIPTION_PENDING("106", "subscription pending for all cm handles"), UNKNOWN_ERROR("108", "Unknown error"), CM_HANDLE_ALREADY_EXIST("109", "cm-handle already exists"), - CM_HANDLE_INVALID_ID("110", "cm-handle has an invalid character(s) in id"); + CM_HANDLE_INVALID_ID("110", "cm-handle has an invalid character(s) in id"), + ALTERNATE_ID_ALREADY_ASSOCIATED("111", "alternate id already associated"); private final String code; private final String message; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index 1f2748b4af..ab83486bd7 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -24,6 +24,7 @@ package org.onap.cps.ncmp.api.impl; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_READY; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST; @@ -50,6 +51,7 @@ import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries; import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; @@ -83,6 +85,7 @@ import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -101,6 +104,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler; private final CpsDataService cpsDataService; private final IMap<String, Object> moduleSyncStartedOnCmHandles; + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; private final TrustLevelManager trustLevelManager; private final AlternateIdChecker alternateIdChecker; @@ -306,45 +310,17 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState(); } - /** - * THis method registers a cm handle and initiates modules sync. - * - * @param dmiPluginRegistration dmi plugin registration information. - * @return cm-handle registration response for create cm-handle requests. - */ - public List<CmHandleRegistrationResponse> parseAndProcessCreatedCmHandlesInRegistration( - final DmiPluginRegistration dmiPluginRegistration, final Collection<String> acceptedCmHandleIds) { - final List<NcmpServiceCmHandle> cmHandlesToBeCreated = dmiPluginRegistration.getCreatedCmHandles(); - final Map<String, TrustLevel> initialTrustLevelPerCmHandleId = new HashMap<>(cmHandlesToBeCreated.size()); - final List<YangModelCmHandle> yangModelCmHandles = new ArrayList<>(cmHandlesToBeCreated.size()); - cmHandlesToBeCreated - .forEach(cmHandle -> { - if (acceptedCmHandleIds.contains(cmHandle.getCmHandleId())) { - final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle( - dmiPluginRegistration.getDmiPlugin(), - dmiPluginRegistration.getDmiDataPlugin(), - dmiPluginRegistration.getDmiModelPlugin(), - cmHandle, - cmHandle.getModuleSetTag(), - cmHandle.getAlternateId()); - yangModelCmHandles.add(yangModelCmHandle); - initialTrustLevelPerCmHandleId.put(cmHandle.getCmHandleId(), - cmHandle.getRegistrationTrustLevel()); - } - }); - return registerNewCmHandles(yangModelCmHandles, initialTrustLevelPerCmHandleId); - } - - protected List<CmHandleRegistrationResponse> parseAndProcessDeletedCmHandlesInRegistration( - final List<String> tobeRemovedCmHandles) { + protected void processRemovedCmHandles(final DmiPluginRegistration dmiPluginRegistration, + final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) { + final List<String> tobeRemovedCmHandleIds = dmiPluginRegistration.getRemovedCmHandles(); final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = - new ArrayList<>(tobeRemovedCmHandles.size()); + new ArrayList<>(tobeRemovedCmHandleIds.size()); final Collection<YangModelCmHandle> yangModelCmHandles = - inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles); + inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandleIds); updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING); final Set<String> notDeletedCmHandles = new HashSet<>(); - for (final List<String> tobeRemovedCmHandleBatch : Lists.partition(tobeRemovedCmHandles, DELETE_BATCH_SIZE)) { + for (final List<String> tobeRemovedCmHandleBatch : Lists.partition(tobeRemovedCmHandleIds, DELETE_BATCH_SIZE)) { try { batchDeleteCmHandlesFromDbAndModuleSyncMap(tobeRemovedCmHandleBatch); tobeRemovedCmHandleBatch.forEach(cmHandleId -> @@ -362,60 +338,58 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService } } } - yangModelCmHandles.removeIf(yangModelCmHandle -> notDeletedCmHandles.contains(yangModelCmHandle.getId())); updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETED); - - return cmHandleRegistrationResponses; + dmiPluginRegistrationResponse.setRemovedCmHandles(cmHandleRegistrationResponses); } - private void processRemovedCmHandles(final DmiPluginRegistration dmiPluginRegistration, + protected void processCreatedCmHandles(final DmiPluginRegistration dmiPluginRegistration, final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) { - if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) { - dmiPluginRegistrationResponse.setRemovedCmHandles( - parseAndProcessDeletedCmHandlesInRegistration(dmiPluginRegistration.getRemovedCmHandles())); - } - } + final List<NcmpServiceCmHandle> ncmpServiceCmHandles = dmiPluginRegistration.getCreatedCmHandles(); + final List<CmHandleRegistrationResponse> failedCmHandleRegistrationResponses = new ArrayList<>(); - private void processCreatedCmHandles(final DmiPluginRegistration dmiPluginRegistration, - final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) { - final Collection<String> acceptedCmHandleIds = alternateIdChecker - .getIdsOfCmHandlesWithAcceptableAlternateId(dmiPluginRegistration.getCreatedCmHandles()); - if (!acceptedCmHandleIds.isEmpty()) { - dmiPluginRegistrationResponse.setCreatedCmHandles( - parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration, acceptedCmHandleIds)); - } - } + try { + final Collection<String> rejectedCmHandleIds + = checkAlternateIds(ncmpServiceCmHandles, failedCmHandleRegistrationResponses); - private void processUpdatedCmHandles(final DmiPluginRegistration dmiPluginRegistration, - final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) { - if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) { - dmiPluginRegistrationResponse.setUpdatedCmHandles( - networkCmProxyDataServicePropertyHandler - .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles())); + final Collection<String> succeededCmHandleIds = persistCmHandlesWithState(dmiPluginRegistration, + dmiPluginRegistrationResponse, ncmpServiceCmHandles, rejectedCmHandleIds); + + processTrustLevels(ncmpServiceCmHandles, succeededCmHandleIds); + + } catch (final AlreadyDefinedException alreadyDefinedException) { + failedCmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponsesFromXpaths( + alreadyDefinedException.getAlreadyDefinedObjectNames(), CM_HANDLE_ALREADY_EXIST)); + } catch (final Exception exception) { + final Collection<String> cmHandleIds = + ncmpServiceCmHandles.stream().map(NcmpServiceCmHandle::getCmHandleId).collect(Collectors.toList()); + failedCmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse + .createFailureResponses(cmHandleIds, exception)); } + final List<CmHandleRegistrationResponse> mergedCmHandleRegistrationResponses + = new ArrayList<>(failedCmHandleRegistrationResponses); + mergedCmHandleRegistrationResponses.addAll(dmiPluginRegistrationResponse.getCreatedCmHandles()); + + dmiPluginRegistrationResponse.setCreatedCmHandles(mergedCmHandleRegistrationResponses); } - private void processUpgradedCmHandles(final DmiPluginRegistration dmiPluginRegistration, - final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) { - if (dmiPluginRegistration.getUpgradedCmHandles() != null - && !dmiPluginRegistration.getUpgradedCmHandles().getCmHandles().isEmpty()) { - dmiPluginRegistrationResponse.setUpgradedCmHandles( - parseAndProcessUpgradedCmHandlesInRegistration(dmiPluginRegistration)); - } + protected void processUpdatedCmHandles(final DmiPluginRegistration dmiPluginRegistration, + final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) { + dmiPluginRegistrationResponse.setUpdatedCmHandles(networkCmProxyDataServicePropertyHandler + .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles())); } + protected void processUpgradedCmHandles( + final DmiPluginRegistration dmiPluginRegistration, + final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) { - protected List<CmHandleRegistrationResponse> parseAndProcessUpgradedCmHandlesInRegistration( - final DmiPluginRegistration dmiPluginRegistration) { - - final List<String> upgradedCmHandleIds = dmiPluginRegistration.getUpgradedCmHandles().getCmHandles(); + final List<String> cmHandleIds = dmiPluginRegistration.getUpgradedCmHandles().getCmHandles(); final String upgradedModuleSetTag = dmiPluginRegistration.getUpgradedCmHandles().getModuleSetTag(); final Map<YangModelCmHandle, CmHandleState> acceptedCmHandleStatePerCmHandle - = new HashMap<>(upgradedCmHandleIds.size()); - final List<CmHandleRegistrationResponse> cmHandleUpgradeResponses = new ArrayList<>(upgradedCmHandleIds.size()); + = new HashMap<>(cmHandleIds.size()); + final List<CmHandleRegistrationResponse> cmHandleUpgradeResponses = new ArrayList<>(cmHandleIds.size()); - for (final String cmHandleId : upgradedCmHandleIds) { + for (final String cmHandleId : cmHandleIds) { try { final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); if (yangModelCmHandle.getCompositeState().getCmHandleState() == CmHandleState.READY) { @@ -442,7 +416,61 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService } } cmHandleUpgradeResponses.addAll(upgradeCmHandles(acceptedCmHandleStatePerCmHandle)); - return cmHandleUpgradeResponses; + dmiPluginRegistrationResponse.setUpgradedCmHandles(cmHandleUpgradeResponses); + } + + private Collection<String> checkAlternateIds( + final List<NcmpServiceCmHandle> cmHandlesToBeCreated, + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses) { + final Collection<String> rejectedCmHandleIds = alternateIdChecker + .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated); + cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses( + rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED)); + return rejectedCmHandleIds; + } + + private List<String> persistCmHandlesWithState(final DmiPluginRegistration dmiPluginRegistration, + final DmiPluginRegistrationResponse dmiPluginRegistrationResponse, + final List<NcmpServiceCmHandle> cmHandlesToBeCreated, + final Collection<String> rejectedCmHandleIds) { + final List<String> succeededCmHandleIds = new ArrayList<>(cmHandlesToBeCreated.size()); + final List<YangModelCmHandle> yangModelCmHandlesToRegister = new ArrayList<>(cmHandlesToBeCreated.size()); + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = + new ArrayList<>(cmHandlesToBeCreated.size()); + for (final NcmpServiceCmHandle ncmpServiceCmHandle: cmHandlesToBeCreated) { + if (!rejectedCmHandleIds.contains(ncmpServiceCmHandle.getCmHandleId())) { + yangModelCmHandlesToRegister.add(getYangModelCmHandle(dmiPluginRegistration, ncmpServiceCmHandle)); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createSuccessResponse(ncmpServiceCmHandle.getCmHandleId())); + succeededCmHandleIds.add(ncmpServiceCmHandle.getCmHandleId()); + } + } + lcmEventsCmHandleStateHandler.initiateStateAdvised(yangModelCmHandlesToRegister); + dmiPluginRegistrationResponse.setCreatedCmHandles(cmHandleRegistrationResponses); + return succeededCmHandleIds; + } + + private YangModelCmHandle getYangModelCmHandle(final DmiPluginRegistration dmiPluginRegistration, + final NcmpServiceCmHandle ncmpServiceCmHandle) { + return YangModelCmHandle.toYangModelCmHandle( + dmiPluginRegistration.getDmiPlugin(), + dmiPluginRegistration.getDmiDataPlugin(), + dmiPluginRegistration.getDmiModelPlugin(), + ncmpServiceCmHandle, + ncmpServiceCmHandle.getModuleSetTag(), + ncmpServiceCmHandle.getAlternateId()); + } + + private void processTrustLevels(final Collection<NcmpServiceCmHandle> cmHandlesToBeCreated, + final Collection<String> succeededCmHandleIds) { + final Map<String, TrustLevel> initialTrustLevelPerCmHandleId = new HashMap<>(cmHandlesToBeCreated.size()); + for (final NcmpServiceCmHandle ncmpServiceCmHandle: cmHandlesToBeCreated) { + if (succeededCmHandleIds.contains(ncmpServiceCmHandle.getCmHandleId())) { + initialTrustLevelPerCmHandleId.put(ncmpServiceCmHandle.getCmHandleId(), + ncmpServiceCmHandle.getRegistrationTrustLevel()); + } + } + trustLevelManager.handleInitialRegistrationOfTrustLevels(initialTrustLevelPerCmHandleId); } private static boolean moduleUpgradeCanBeSkipped(final YangModelCmHandle yangModelCmHandle, @@ -488,15 +516,14 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private void deleteCmHandleFromDbAndModuleSyncMap(final String cmHandleId) { inventoryPersistence.deleteSchemaSetWithCascade(cmHandleId); - inventoryPersistence.deleteDataNode(NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId - + "']"); + inventoryPersistence.deleteDataNode(NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']"); removeDeletedCmHandleFromModuleSyncMap(cmHandleId); } - private void batchDeleteCmHandlesFromDbAndModuleSyncMap(final Collection<String> tobeRemovedCmHandles) { - inventoryPersistence.deleteSchemaSetsWithCascade(tobeRemovedCmHandles); - inventoryPersistence.deleteDataNodes(mapCmHandleIdsToXpaths(tobeRemovedCmHandles)); - tobeRemovedCmHandles.forEach(this::removeDeletedCmHandleFromModuleSyncMap); + private void batchDeleteCmHandlesFromDbAndModuleSyncMap(final Collection<String> cmHandleIds) { + inventoryPersistence.deleteSchemaSetsWithCascade(cmHandleIds); + inventoryPersistence.deleteDataNodes(mapCmHandleIdsToXpaths(cmHandleIds)); + cmHandleIds.forEach(this::removeDeletedCmHandleFromModuleSyncMap); } private Collection<String> mapCmHandleIdsToXpaths(final Collection<String> cmHandles) { @@ -506,25 +533,9 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService } // CPS-1239 Robustness cleaning of in progress cache - private void removeDeletedCmHandleFromModuleSyncMap(final String deletedCmHandleId) { - if (moduleSyncStartedOnCmHandles.remove(deletedCmHandleId) != null) { - log.debug("{} removed from in progress map", deletedCmHandleId); - } - } - - private List<CmHandleRegistrationResponse> registerNewCmHandles(final List<YangModelCmHandle> yangModelCmHandles, - final Map<String, TrustLevel> - initialTrustLevelPerCmHandleId) { - final Set<String> cmHandleIds = initialTrustLevelPerCmHandleId.keySet(); - try { - lcmEventsCmHandleStateHandler.initiateStateAdvised(yangModelCmHandles); - trustLevelManager.handleInitialRegistrationOfTrustLevels(initialTrustLevelPerCmHandleId); - return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds); - } catch (final AlreadyDefinedException alreadyDefinedException) { - return CmHandleRegistrationResponse.createFailureResponses( - alreadyDefinedException.getAlreadyDefinedObjectNames(), CM_HANDLE_ALREADY_EXIST); - } catch (final Exception exception) { - return CmHandleRegistrationResponse.createFailureResponses(cmHandleIds, exception); + private void removeDeletedCmHandleFromModuleSyncMap(final String cmHandleId) { + if (moduleSyncStartedOnCmHandles.remove(cmHandleId) != null) { + log.debug("{} removed from in progress map", cmHandleId); } } @@ -553,6 +564,4 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService } } - - } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java index 1478c86c24..f5d22af281 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java @@ -77,7 +77,8 @@ public class NetworkCmProxyDataServicePropertyHandler { */ public List<CmHandleRegistrationResponse> updateCmHandleProperties( final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) { - final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(); + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses + = new ArrayList<>(ncmpServiceCmHandles.size()); for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) { final String cmHandleId = ncmpServiceCmHandle.getCmHandleId(); try { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java index 171db52998..f12cc9c822 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java @@ -30,6 +30,10 @@ import org.springframework.context.annotation.Configuration; @Configuration public class TrustLevelCacheConfig extends HazelcastCacheConfig { + public static final String TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME = "trustLevelPerDmiPlugin"; + + public static final String TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME = "trustLevelPerCmHandle"; + private static final MapConfig trustLevelPerCmHandleCacheConfig = createMapConfig("trustLevelPerCmHandleCacheConfig"); @@ -41,7 +45,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of cm handle name as keys to trust-level for values. */ - @Bean + @Bean(TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) public Map<String, TrustLevel> trustLevelPerCmHandle() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerCmHandleMap", trustLevelPerCmHandleCacheConfig).getMap("trustLevelPerCmHandle"); @@ -52,7 +56,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of dmi-plugin name as keys to trust-level for values. */ - @Bean + @Bean(TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) public Map<String, TrustLevel> trustLevelPerDmiPlugin() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerDmiPluginMap", trustLevelPerDmiPluginCacheConfig).getMap("trustLevelPerDmiPlugin"); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducer.java new file mode 100644 index 0000000000..5c192a953f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducer.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.cmsubscription; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import java.net.URI; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.events.EventsPublisher; +import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent; +import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) +public class CmNotificationSubscriptionDmiInEventProducer { + + private final EventsPublisher<CloudEvent> eventsPublisher; + private final JsonObjectMapper jsonObjectMapper; + + @Value("${app.ncmp.avc.subscription-forward-topic-prefix}") + private String cmNotificationSubscriptionDmiInEventTopic; + + /** + * Publish the event to the provided dmi plugin with key as subscription id and the event is in Cloud Event format. + * + * @param subscriptionId Cm Subscription Id + * @param dmiPluginName Dmi Plugin Name + * @param eventType Type of event + * @param cmNotificationSubscriptionDmiInEvent Cm Notification Subscription event for Dmi + */ + public void publishCmNotificationSubscriptionDmiInEvent(final String subscriptionId, final String dmiPluginName, + final String eventType, final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent) { + eventsPublisher.publishCloudEvent(cmNotificationSubscriptionDmiInEventTopic, subscriptionId, + buildAndGetCmNotificationDmiInEventAsCloudEvent(subscriptionId, dmiPluginName, eventType, + cmNotificationSubscriptionDmiInEvent)); + + } + + private CloudEvent buildAndGetCmNotificationDmiInEventAsCloudEvent(final String subscriptionId, + final String dmiPluginName, final String eventType, + final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent) { + return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withType(eventType) + .withSource(URI.create("NCMP")).withDataSchema(URI.create("org.onap.ncmp.dmi.cm.subscription:1.0.0")) + .withExtension("correlationid", subscriptionId.concat("#").concat(dmiPluginName)) + .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionDmiInEvent)).build(); + } + + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumer.java new file mode 100644 index 0000000000..ea72fd217b --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumer.java @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.cmsubscription; + +import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent; + +import io.cloudevents.CloudEvent; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class CmNotificationSubscriptionDmiOutEventConsumer { + + /** + * Consume the Cm Notification Subscription event from the dmi-plugin. + * + * @param cmNotificationSubscriptionDmiOutEventConsumerRecord the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", + containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") + public void consumeCmNotificationSubscriptionDmiOutEvent( + final ConsumerRecord<String, CloudEvent> cmNotificationSubscriptionDmiOutEventConsumerRecord) { + final CloudEvent cloudEvent = cmNotificationSubscriptionDmiOutEventConsumerRecord.value(); + final CmNotificationSubscriptionDmiOutEvent cmNotificationSubscriptionDmiOutEvent = + toTargetEvent(cloudEvent, CmNotificationSubscriptionDmiOutEvent.class); + final String correlationId = String.valueOf(cloudEvent.getExtension("correlationid")); + if ("subscriptionCreateResponse".equals(cloudEvent.getType()) && cmNotificationSubscriptionDmiOutEvent != null + && correlationId != null) { + handleCmSubscriptionCreate(correlationId, cmNotificationSubscriptionDmiOutEvent); + } + } + + private void handleCmSubscriptionCreate(final String correlationId, + final CmNotificationSubscriptionDmiOutEvent cmNotificationSubscriptionDmiOutEvent) { + final String subscriptionId = correlationId.split("#")[0]; + final String dmiPluginName = correlationId.split("#")[1]; + log.info("Cm Subscription with id : {} handled by the dmi-plugin : {} has the status : {}", subscriptionId, + dmiPluginName, cmNotificationSubscriptionDmiOutEvent.getData().getStatusMessage()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java index bc798afeed..d3bde011b3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java @@ -37,9 +37,6 @@ public class CmNotificationSubscriptionNcmpInEventConsumer { @Value("${notification.enabled:true}") private boolean notificationFeatureEnabled; - @Value("${ncmp.model-loader.subscription:false}") - private boolean subscriptionModelLoaderEnabled; - /** * Consume the specified event. * @@ -51,10 +48,8 @@ public class CmNotificationSubscriptionNcmpInEventConsumer { final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value(); final CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent = toTargetEvent(cloudEvent, CmNotificationSubscriptionNcmpInEvent.class); - if (subscriptionModelLoaderEnabled) { - log.info("Subscription with name {} to be mapped to hazelcast object...", - cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId()); - } + log.info("Subscription with name {} to be mapped to hazelcast object...", + cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId()); if ("subscriptionCreated".equals(cloudEvent.getType()) && cmNotificationSubscriptionNcmpInEvent != null) { log.info("Subscription for ClientID {} with name {} ...", cloudEvent.getSource(), cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId()); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java index 2d7ad698c5..a43da294c1 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java @@ -34,12 +34,14 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.inventory.enums.PropertyType; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.utils.CpsValidator; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @RequiredArgsConstructor @@ -49,7 +51,11 @@ public class CmHandleQueriesImpl implements CmHandleQueries { private static final String DESCENDANT_PATH = "//"; private static final String ANCESTOR_CM_HANDLES = "/ancestor::cm-handles"; private final CpsDataPersistenceService cpsDataPersistenceService; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerCmHandle; private final CpsValidator cpsValidator; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java index 22f18cd243..4c606a9c01 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java @@ -24,10 +24,12 @@ import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Slf4j @@ -35,7 +37,10 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class TrustLevelManager { + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerCmHandle; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; private final InventoryPersistence inventoryPersistence; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java index 6ae7ff3d4e..78eaf3e6bf 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java @@ -26,8 +26,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -40,6 +42,8 @@ public class DmiPluginWatchDog { private final NetworkCmProxyDataService networkCmProxyDataService; private final TrustLevelManager trustLevelManager; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java index 1be1a90853..4ac6537494 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java @@ -103,10 +103,10 @@ public class AlternateIdChecker { * @param newNcmpServiceCmHandles the proposed new cm handles * @return collection of cm handles ids which are acceptable */ - public Collection<String> getIdsOfCmHandlesWithAcceptableAlternateId( + public Collection<String> getIdsOfCmHandlesWithRejectedAlternateId( final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles) { final Set<String> acceptedAlternateIds = new HashSet<>(newNcmpServiceCmHandles.size()); - final Collection<String> acceptedCmHandleIds = new ArrayList<>(newNcmpServiceCmHandles.size()); + final Collection<String> rejectedCmHandleIds = new ArrayList<>(); for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) { final String cmHandleId = ncmpServiceCmHandle.getCmHandleId(); final String proposedAlternateId = ncmpServiceCmHandle.getAlternateId(); @@ -124,10 +124,11 @@ public class AlternateIdChecker { } if (isAcceptable) { acceptedAlternateIds.add(proposedAlternateId); - acceptedCmHandleIds.add(cmHandleId); + } else { + rejectedCmHandleIds.add(cmHandleId); } } - return acceptedCmHandleIds; + return rejectedCmHandleIds; } private boolean alternateIdAlreadyInDb(final String alternateId) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java index 82283228a1..52b8d6926a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java @@ -1,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Bell Canada - * Modifications Copyright (C) 2022-2023 Nordix Foundation + * Modifications Copyright (C) 2022-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,20 +76,22 @@ public class CmHandleRegistrationResponse { } /** - * Creates a failure response based on registration error. + * Create a failure response of cm handle registration based on xpath and registration error. + * Conditions: + * - the xpath should be valid according to the cps path, otherwise xpath is not included in the response. * - * @param failedXpaths list of failed Xpaths - * @param ncmpResponseStatus enum describing the type of registration error - * @return CmHandleRegistrationResponse + * @param failedXpaths the failed xpaths + * @param ncmpResponseStatus type of the registration error + * @return collection of cm handle registration response */ - public static List<CmHandleRegistrationResponse> createFailureResponses(final Collection<String> failedXpaths, - final NcmpResponseStatus ncmpResponseStatus) { + public static List<CmHandleRegistrationResponse> createFailureResponsesFromXpaths( + final Collection<String> failedXpaths, final NcmpResponseStatus ncmpResponseStatus) { final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failedXpaths.size()); for (final String xpath : failedXpaths) { try { final String cmHandleId = YangDataConverter.extractCmHandleIdFromXpath(xpath); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, ncmpResponseStatus)); + cmHandleRegistrationResponses + .add(CmHandleRegistrationResponse.createFailureResponse(cmHandleId, ncmpResponseStatus)); } catch (IllegalArgumentException | IllegalStateException e) { log.warn("Unexpected xpath {}", xpath); } @@ -98,6 +100,24 @@ public class CmHandleRegistrationResponse { } /** + * Create a failure response of cm handle registration based on cm handle id and registration error. + * + * @param failedCmHandleIds the failed cm handle ids + * @param ncmpResponseStatus type of the registration error + * @return collection of cm handle registration response + */ + public static List<CmHandleRegistrationResponse> createFailureResponses( + final Collection<String> failedCmHandleIds, final NcmpResponseStatus ncmpResponseStatus) { + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = + new ArrayList<>(failedCmHandleIds.size()); + for (final String failedCmHandleId : failedCmHandleIds) { + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(failedCmHandleId, ncmpResponseStatus)); + } + return cmHandleRegistrationResponses; + } + + /** * Creates a failure response based on other exception. * * @param cmHandleIds list of failed cmHandleIds diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java index 4615af61c1..7d6a8e1407 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation + * Copyright (C) 2021-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,7 @@ public class DmiPluginRegistration { private List<String> removedCmHandles = Collections.emptyList(); - private UpgradedCmHandles upgradedCmHandles; + private UpgradedCmHandles upgradedCmHandles = new UpgradedCmHandles(); /** * Validates plugin service names. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java index 7cee87a2a0..4c31719a29 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java @@ -32,7 +32,6 @@ import org.onap.cps.api.CpsModuleService; import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException; import org.onap.cps.ncmp.api.impl.operations.DatastoreType; import org.onap.cps.spi.exceptions.AlreadyDefinedException; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Slf4j @@ -45,24 +44,16 @@ public class CmDataSubscriptionModelLoader extends AbstractModelLoader { private static final String REGISTRY_DATANODE_NAME = "datastores"; public CmDataSubscriptionModelLoader(final CpsDataspaceService cpsDataspaceService, - final CpsModuleService cpsModuleService, - final CpsAnchorService cpsAnchorService, - final CpsDataService cpsDataService) { + final CpsModuleService cpsModuleService, final CpsAnchorService cpsAnchorService, + final CpsDataService cpsDataService) { super(cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService); } - @Value("${ncmp.model-loader.subscription:true}") - private boolean subscriptionModelLoaderEnabled; - @Override public void onboardOrUpgradeModel() { - if (subscriptionModelLoaderEnabled) { - waitUntilDataspaceIsAvailable(NCMP_DATASPACE_NAME); - onboardSubscriptionModels(); - log.info("Subscription Models onboarded successfully"); - } else { - log.info("Subscription Model Loader is disabled"); - } + waitUntilDataspaceIsAvailable(NCMP_DATASPACE_NAME); + onboardSubscriptionModels(); + log.info("Subscription Models onboarded successfully"); } private void onboardSubscriptionModels() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index 313d1b4afd..cb7e1ef8a9 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -27,7 +27,6 @@ import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR -import java.util.stream.Collectors import org.onap.cps.ncmp.api.impl.inventory.CompositeState import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker @@ -71,12 +70,18 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def trustLevelPerDmiPlugin = [:] def mockTrustLevelManager = Mock(TrustLevelManager) def mockAlternateIdChecker = Mock(AlternateIdChecker) - def objectUnderTest = getObjectUnderTest() + + def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations, + mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmHandleQueries, + stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService, + mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockAlternateIdChecker)) def setup() { // always accept all cm handles - mockAlternateIdChecker.getIdsOfCmHandlesWithAcceptableAlternateId(_) >> - { args -> args[0].stream().map(it -> it.cmHandleId).collect(Collectors.toList()) } + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] + + // always can find all cm handles in DB + mockInventoryPersistence.getYangModelCmHandles(_) >> { args -> args[0].collect { new YangModelCmHandle(id:it) } } } def 'DMI Registration: Create, Update, Delete & Upgrade operations are processed in the right order'() { @@ -94,15 +99,16 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { when: 'registration is processed' objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration) then: 'cm-handles are removed first' - 1 * objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_) + 1 * objectUnderTest.processRemovedCmHandles(*_) and: 'de-registered cm handle entry is removed from in progress map' 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2') then: 'cm-handles are created' - 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_) + 1 * objectUnderTest.processCreatedCmHandles(*_) then: 'cm-handles are updated' - 1 * mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) + 1 * objectUnderTest.processUpdatedCmHandles(*_) + 1 * mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) >> [] then: 'cm-handles are upgraded' - 1 * objectUnderTest.parseAndProcessUpgradedCmHandlesInRegistration(*_) + 1 * objectUnderTest.processUpgradedCmHandles(*_) } def 'DMI Registration upgrade operation with upgrade node state #scenario'() { @@ -137,29 +143,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'cm handle is invalid' | new DataValidationException('some error message', 'some error details') || '110' } - def 'DMI Registration: Response from all operations types are in response'() { - given: 'a registration with operations of all three types' - def dmiRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server') - dmiRegistration.setCreatedCmHandles([new NcmpServiceCmHandle(cmHandleId: 'cmhandle-1', publicProperties: ['publicProp1': 'value'], dmiProperties: [:])]) - dmiRegistration.setUpdatedCmHandles([new NcmpServiceCmHandle(cmHandleId: 'cmhandle-2', publicProperties: ['publicProp1': 'value'], dmiProperties: [:])]) - dmiRegistration.setRemovedCmHandles(['cmhandle-2']) - and: 'update cm-handles can be processed successfully' - def updateResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-2')] - mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) >> updateResponses - and: 'create cm-handles can be processed successfully' - def createdResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-1')] - objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_) >> createdResponses - and: 'delete cm-handles can be processed successfully' - def removeResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-3')] - objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_) >> removeResponses - when: 'registration is processed' - def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration) - then: 'response has values from all operations' - response.removedCmHandles == removeResponses - response.createdCmHandles == createdResponses - response.updatedCmHandles == updateResponses - } - def 'Create CM-handle Validation: Registration with valid Service names: #scenario'() { given: 'a registration ' def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: dmiPlugin, dmiModelPlugin: dmiModelPlugin, @@ -168,7 +151,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { when: 'update registration and sync module is called with correct DMI plugin information' objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'create cm handles registration and sync modules is called with the correct plugin information' - 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration, _) + 1 * objectUnderTest.processCreatedCmHandles(dmiPluginRegistration, _) and: 'dmi is added to the dmi trustLevel map' assert trustLevelPerDmiPlugin.size() == 1 assert trustLevelPerDmiPlugin.containsKey(expectedDmiPluginRegisteredName) @@ -190,7 +173,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def exceptionThrown = thrown(DmiRequestException.class) assert exceptionThrown.getMessage().contains(expectedMessageDetails) and: 'registration is not called' - 0 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration) + 0 * objectUnderTest.processCreatedCmHandles(*_) where: scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedMessageDetails 'empty DMI plugins' | '' | '' | '' || 'No DMI plugin service names' @@ -231,22 +214,18 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'without dmi & public properties' | [:] | [:] || [:] | [:] } - def 'Add CM-Handle to trustLevelPerCmHandle Successfully with: #scenario.'() { - given: 'a registration with trustLevel and populated cache' - def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server') - dmiPluginRegistration.createdCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', registrationTrustLevel: TrustLevel.NONE), - new NcmpServiceCmHandle(cmHandleId: cmHandleId, registrationTrustLevel: registrationTrustLevel)] + def 'Add CM-Handle #scenario.'() { + given: ' registration details for one cm handles' + def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', + createdCmHandles:[new NcmpServiceCmHandle(cmHandleId: 'ch-1', registrationTrustLevel: registrationTrustLevel)]) when: 'registration is updated' - def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - then: 'a successful response is received' - assert response.createdCmHandles.size() == expectedNumberOfCreatedCmHandles - and: 'trustLevel is set for the created cm-handle' - 1 * mockTrustLevelManager.handleInitialRegistrationOfTrustLevels(_) + objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) + then: 'trustLevel is set for the created cm-handle' + 1 * mockTrustLevelManager.handleInitialRegistrationOfTrustLevels(expectedMapping) where: - scenario | cmHandleId | registrationTrustLevel || expectedNumberOfCreatedCmHandles - 'new trusted cm handle' | 'ch-new' | TrustLevel.COMPLETE || 2 - 'existing cm handle without trust level' | 'ch-1' | null || 1 - 'new cm handle without trust level' | 'ch-new' | null || 2 + scenario | registrationTrustLevel || expectedMapping + 'with trusted cm handle' | TrustLevel.COMPLETE || [ 'ch-1' : TrustLevel.COMPLETE ] + 'without trust level' | null || [ 'ch-1' : null ] } def 'Create CM-Handle Multiple Requests: All cm-handles creation requests are processed with some failures'() { @@ -311,17 +290,15 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def 'Remove CmHandle Successfully: #scenario'() { given: 'a registration' - addPersistedYangModelCmHandles(['cmhandle']) - def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', - removedCmHandles: ['cmhandle']) + def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', removedCmHandles: ['cmhandle']) and: '#scenario' - mockCpsModuleService.deleteSchemaSetsWithCascade(_, ['cmhandle']) >> - { if (!schemaSetExist) { throw new SchemaSetNotFoundException("", "") } } + mockCpsModuleService.deleteSchemaSetsWithCascade(_, ['cmhandle']) >> { if (!schemaSetExist) { throw new SchemaSetNotFoundException('', '') } } when: 'registration is updated to delete cmhandle' def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'the cmHandle state is updated to "DELETING"' - 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) - and: 'method to delete relevant schema set is called once' + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> + { args -> args[0].values()[0] == CmHandleState.DELETING } + then: 'method to delete relevant schema set is called once' 1 * mockInventoryPersistence.deleteSchemaSetsWithCascade(_) and: 'method to delete relevant list/list element is called once' 1 * mockInventoryPersistence.deleteDataNodes(_) @@ -332,7 +309,10 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { assert it.cmHandle == 'cmhandle' } and: 'the cmHandle state is updated to "DELETED"' - 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> + { args -> args[0].values()[0] == CmHandleState.DELETED } + and: 'No cm handles state updates for "upgraded cm handles"' + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch([:]) where: scenario | schemaSetExist 'schema-set exists and can be deleted successfully' | true @@ -340,9 +320,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { } def 'Remove CmHandle: Partial Success'() { - given: 'some unique yang model cm handles' - addPersistedYangModelCmHandles(['cmhandle1', 'cmhandle2', 'cmhandle3']) - and: 'a registration with three cm-handles to be deleted' + given: 'a registration with three cm-handles to be deleted' def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', removedCmHandles: ['cmhandle1', 'cmhandle2', 'cmhandle3']) and: 'cm-handle deletion fails on batch' @@ -359,7 +337,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle1') and: 'successfully de-registered cm handle 3 is removed from in progress map even though it was already being removed' 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle3') >> 'already in progress' - and: 'failed de-registered cm handle entries should not be removed from in progress map' + and: 'failed de-registered cm handle entries should NOT be removed from in progress map' 0 * mockModuleSyncStartedOnCmHandles.remove('cmhandle2') and: '1st and 3rd cm-handle deletes successfully' with(response.removedCmHandles[0]) { @@ -382,11 +360,13 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { assert it.size() == 2 assert it.every { entry -> entry.value == CmHandleState.DELETED } }) + and: 'No cm handles state updates for "upgraded cm handles"' + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch([:]) + } def 'Remove CmHandle Error Handling: Schema Set Deletion failed'() { given: 'a registration' - addPersistedYangModelCmHandles(['cmhandle']) def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', removedCmHandles: ['cmhandle']) and: 'schema set batch deletion failed with unknown error' @@ -413,7 +393,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def 'Remove CmHandle Error Handling: #scenario'() { given: 'a registration' - addPersistedYangModelCmHandles(['cmhandle']) def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', removedCmHandles: ['cmhandle']) and: 'cm-handle deletion fails on batch' @@ -446,18 +425,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { when: 'the DMI plugin registration happens' objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'the new alternate id is added to the cache' - 1 * mockAlternateIdChecker.getIdsOfCmHandlesWithAcceptableAlternateId(ncmpServiceCmHandles) >> ['cmhandle1'] + 1 * mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(ncmpServiceCmHandles) >> ['cmhandle1'] } - def getObjectUnderTest() { - return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations, - mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmHandleQueries, - stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService, - mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockAlternateIdChecker)) - } - - def addPersistedYangModelCmHandles(ids) { - def yangModelCmHandles = ids.collect { new YangModelCmHandle(id:it) } - mockInventoryPersistence.getYangModelCmHandles(ids) >> yangModelCmHandles - } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index fc548ebe9b..9b4fe146b9 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -23,6 +23,8 @@ package org.onap.cps.ncmp.api.impl +import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse + import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR @@ -270,8 +272,11 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { dmiDataPlugin: 'service2') dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle] mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle] + and: 'no rejected cm handles because of alternate ids' + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] when: 'parse and create cm handle in dmi registration then sync module' - objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration, ['test-cm-handle-id']) + mockDmiPluginRegistration.createdCmHandles = ['test-cm-handle-id'] + objectUnderTest.processCreatedCmHandles(mockDmiPluginRegistration, new DmiPluginRegistrationResponse()) then: 'system persists the cm handle state' 1 * mockLcmEventsCmHandleStateHandler.initiateStateAdvised(_) >> { args -> { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy new file mode 100644 index 0000000000..cd9b8ddf41 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.cmsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.CloudEvent +import org.onap.cps.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper +import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent +import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Cmhandle +import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Data +import org.onap.cps.utils.JsonObjectMapper +import spock.lang.Specification + +class CmNotificationSubscriptionDmiInEventProducerSpec extends Specification { + + def mockEventsPublisher = Mock(EventsPublisher) + def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) + + def objectUnderTest = new CmNotificationSubscriptionDmiInEventProducer(mockEventsPublisher, jsonObjectMapper) + + def 'Create and Publish Cm Notification Subscription DMI In Event'() { + given: 'a cm subscription for a dmi plugin' + def subscriptionId = 'test-subscription-id' + def dmiPluginName = 'test-dmiplugin' + def eventType = 'subscriptionCreateRequest' + def cmNotificationSubscriptionDmiInEvent = new CmNotificationSubscriptionDmiInEvent(data: new Data(cmhandles: [new Cmhandle(cmhandleId: 'test-1', privateProperties: [:])])) + and: 'also we have target topic for dmiPlugin' + objectUnderTest.cmNotificationSubscriptionDmiInEventTopic = 'dmiplugin-test-topic' + when: 'the event is published' + objectUnderTest.publishCmNotificationSubscriptionDmiInEvent(subscriptionId, dmiPluginName, eventType, cmNotificationSubscriptionDmiInEvent) + then: 'the event contains the required attributes' + 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { + args -> + { + assert args[0] == 'dmiplugin-test-topic' + assert args[1] == subscriptionId + def cmNotificationSubscriptionDmiInEventAsCloudEvent = (args[2] as CloudEvent) + assert cmNotificationSubscriptionDmiInEventAsCloudEvent.getExtension('correlationid') == subscriptionId + '#' + dmiPluginName + assert cmNotificationSubscriptionDmiInEventAsCloudEvent.type == 'subscriptionCreateRequest' + assert cmNotificationSubscriptionDmiInEventAsCloudEvent.source.toString() == 'NCMP' + assert CloudEventMapper.toTargetEvent(cmNotificationSubscriptionDmiInEventAsCloudEvent, CmNotificationSubscriptionDmiInEvent) == cmNotificationSubscriptionDmiInEvent + } + } + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy new file mode 100644 index 0000000000..4f0132e2bd --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy @@ -0,0 +1,85 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.cmsubscription + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.Logger +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.read.ListAppender +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.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec { + + def objectUnderTest = new CmNotificationSubscriptionDmiOutEventConsumer() + def logger = Spy(ListAppender<ILoggingEvent>) + + @Autowired + JsonObjectMapper jsonObjectMapper + + @Autowired + ObjectMapper objectMapper + + void setup() { + ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionDmiOutEventConsumer.class)).addAppender(logger) + logger.start() + } + + void cleanup() { + ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionDmiOutEventConsumer.class)).detachAndStopAllAppenders() + } + + + def 'Consume valid CM Subscription response from DMI Plugin'() { + given: 'a cmsubscription event' + def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionDmiOutEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionDmiOutEvent.class) + def testCloudEventSent = CloudEventBuilder.v1() + .withData(objectMapper.writeValueAsBytes(testEventSent)) + .withId('random-uuid') + .withType('subscriptionCreateResponse') + .withSource(URI.create('test-dmi-plugin-name')) + .withExtension('correlationid', 'sub-1#test-dmi-plugin-name').build() + def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent) + when: 'the valid event is consumed' + objectUnderTest.consumeCmNotificationSubscriptionDmiOutEvent(consumerRecord) + then: 'an event is logged with level INFO' + def loggingEvent = getLoggingEvent() + assert loggingEvent.level == Level.INFO + and: 'the log indicates the task completed successfully' + assert loggingEvent.formattedMessage == 'Cm Subscription with id : sub-1 handled by the dmi-plugin : test-dmi-plugin-name has the status : accepted' + } + + def getLoggingEvent() { + return logger.list[0] + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy index 6a3d4bef7b..1074229489 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy @@ -71,8 +71,6 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent) and: 'notifications are enabled' objectUnderTest.notificationFeatureEnabled = true - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = true when: 'the valid event is consumed' objectUnderTest.consumeSubscriptionEvent(consumerRecord) then: 'an event is logged with level INFO' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy index f41fd6cdf3..aaa034437c 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy @@ -76,17 +76,17 @@ class AlternateIdCheckerSpec extends Specification { mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> { args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } when: 'the batch of new cm handles is checked' - def result = objectUnderTest.getIdsOfCmHandlesWithAcceptableAlternateId(batch) + def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch) then: 'the result only contains the ids of the acceptable cm handles' - assert result.contains('ch-1') == acceptCh1 - assert result.contains('ch-2') == acceptCh2 + assert result.contains('ch-1') == rejectCh1 + assert result.contains('ch-2') == rejectCh2 where: 'the following alternate ids are used' - scenario | alt1 | alt2 | altAlreadyInDb || acceptCh1 | acceptCh2 - 'no alternate ids' | '' | '' | ['dont matter'] || true | true - 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || true | true - 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || false | true - 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || false | false - 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || true | false + scenario | alt1 | alt2 | altAlreadyInDb || rejectCh1 | rejectCh2 + 'no alternate ids' | '' | '' | ['dont matter'] || false | false + 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || false | false + 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || true | false + 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || true | true + 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || false | true } def throwDataNodeNotFoundException() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy index d76f912234..7803ae319f 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy @@ -1,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Bell Canada - * Modifications Copyright (C) 2023 Nordix Foundation + * Modifications Copyright (C) 2023-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ package org.onap.cps.ncmp.api.models +import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR @@ -71,7 +72,7 @@ class CmHandleRegistrationResponseSpec extends Specification { def 'Failed cm-handle Registration with multiple responses.'() { when: 'cm-handle failure response is created for 2 xpaths' def cmHandleRegistrationResponses = - CmHandleRegistrationResponse.createFailureResponses(["somePathWithId[@id='123']","somePathWithId[@id='456']"], CM_HANDLE_ALREADY_EXIST) + CmHandleRegistrationResponse.createFailureResponsesFromXpaths(["somePathWithId[@id='123']", "somePathWithId[@id='456']"], CM_HANDLE_ALREADY_EXIST) then: 'the response has the correct cm handle ids' assert cmHandleRegistrationResponses.size() == 2 assert cmHandleRegistrationResponses.stream().map(it -> it.cmHandle).collect(Collectors.toList()) @@ -81,9 +82,20 @@ class CmHandleRegistrationResponseSpec extends Specification { def 'Failed cm-handle Registration with multiple responses with an unexpected xpath.'() { when: 'cm-handle failure response is created for one valid and one unexpected xpath' def cmHandleRegistrationResponses = - CmHandleRegistrationResponse.createFailureResponses(["somePathWithId[@id='123']","valid/xpath/without-id[@key='123']"], CM_HANDLE_ALREADY_EXIST) + CmHandleRegistrationResponse.createFailureResponsesFromXpaths(["somePathWithId[@id='123']", "valid/xpath/without-id[@key='123']"], CM_HANDLE_ALREADY_EXIST) then: 'the response has only one entry' assert cmHandleRegistrationResponses.size() == 1 } + def 'Failed cm-handle registration based on cm handle id and registration error'() { + when: 'the failure response is created with "alternate id already associated" error code for 1 cm handle' + def cmHandleRegistrationResponses = + CmHandleRegistrationResponse.createFailureResponses(['ch 1'], ALTERNATE_ID_ALREADY_ASSOCIATED) + then: 'the response with expected values' + assert cmHandleRegistrationResponses[0].cmHandle == 'ch 1' + assert cmHandleRegistrationResponses[0].status == Status.FAILURE + assert cmHandleRegistrationResponses[0].ncmpResponseStatus == ALTERNATE_ID_ALREADY_ASSOCIATED + assert cmHandleRegistrationResponses[0].errorText == 'alternate id already associated' + } + } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy index bde9961c2f..f3b405b117 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy @@ -20,24 +20,23 @@ package org.onap.cps.ncmp.init -import org.onap.cps.api.CpsAnchorService -import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException -import org.onap.cps.spi.exceptions.AlreadyDefinedException - -import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME - import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger import ch.qos.logback.core.read.ListAppender -import org.onap.cps.api.CpsDataspaceService +import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataService +import org.onap.cps.api.CpsDataspaceService import org.onap.cps.api.CpsModuleService +import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException +import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.model.Dataspace import org.slf4j.LoggerFactory import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.annotation.AnnotationConfigApplicationContext import spock.lang.Specification +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME + class CmDataSubscriptionModelLoaderSpec extends Specification { def mockCpsDataspaceService = Mock(CpsDataspaceService) @@ -67,9 +66,7 @@ class CmDataSubscriptionModelLoaderSpec extends Specification { } def 'Onboard subscription model via application ready event.'() { - given:'model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = true - and: 'dataspace is ready for use' + given: 'dataspace is ready for use' mockCpsDataspaceService.getDataspace(NCMP_DATASPACE_NAME) >> new Dataspace('') when: 'the application is ready' objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent)) @@ -81,14 +78,14 @@ class CmDataSubscriptionModelLoaderSpec extends Specification { 1 * mockCpsDataService.saveData(NCMP_DATASPACE_NAME, 'cm-data-subscriptions', '{"datastores":{}}', _) and: 'the data service is called once to create datastore for Passthrough-operational' 1 * mockCpsDataService.saveData(NCMP_DATASPACE_NAME, 'cm-data-subscriptions', '/datastores', - '{"datastore":[{"name":"ncmp-datastore:passthrough-operational","cm-handles":{}}]}', _, _) + '{"datastore":[{"name":"ncmp-datastore:passthrough-operational","cm-handles":{}}]}', _, _) and: 'the data service is called once to create datastore for Passthrough-running' 1 * mockCpsDataService.saveData(NCMP_DATASPACE_NAME, 'cm-data-subscriptions', '/datastores', - '{"datastore":[{"name":"ncmp-datastore:passthrough-running","cm-handles":{}}]}', _, _) + '{"datastore":[{"name":"ncmp-datastore:passthrough-running","cm-handles":{}}]}', _, _) } def 'Create node for datastore with already defined exception.'() { - given:'the data service throws an Already Defined exception' + given: 'the data service throws an Already Defined exception' mockCpsDataService.saveData(*_) >> { throw AlreadyDefinedException.forDataNodes([], 'some context') } when: 'attempt to create datastore' objectUnderTest.createDatastore('some datastore') @@ -110,16 +107,4 @@ class CmDataSubscriptionModelLoaderSpec extends Specification { assert thrown.details.contains('test message') } - def 'Subscription model loader disabled.' () { - given: 'model loader is disabled' - objectUnderTest.subscriptionModelLoaderEnabled = false - when: 'application is ready' - objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent)) - then: 'no interaction with admin service' - 0 * mockCpsDataspaceService.getDataspace(_) - then: 'a message is logged that the function is disabled' - def logs = loggingListAppender.list.toString() - assert logs.contains('Subscription Model Loader is disabled') - } - } diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml index a4bb4e8124..a3283ff40f 100644 --- a/cps-ncmp-service/src/test/resources/application.yml +++ b/cps-ncmp-service/src/test/resources/application.yml @@ -50,8 +50,6 @@ ncmp: async-executor: parallelism-level: 3 - model-loader: - subscription: true # Custom Hazelcast Config. hazelcast: diff --git a/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionDmiOutEvent.json b/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionDmiOutEvent.json new file mode 100644 index 0000000000..f0b78fb7c8 --- /dev/null +++ b/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionDmiOutEvent.json @@ -0,0 +1,6 @@ +{ + "data": { + "statusCode": "1", + "statusMessage": "accepted" + } +}
\ No newline at end of file |