From b3b44d9aa4e71c4264df140ffff27b5ba4c44e82 Mon Sep 17 00:00:00 2001 From: "halil.cakal" Date: Tue, 6 Jun 2023 16:20:55 +0100 Subject: Agreed outstanding comments including package refactoring - Change package of AVC Subscription relevent codes into their place - Change package of Subscription Event Cache config inot its place - Add more branches for subscription outcome mapper - Add more branches for subscription event response consumer - Change unit test method params in order not to use deprecated methods Issue-ID: CPS-1730 Change-Id: Ieda587d5be318db8360d52d49dc38d7ce3dd85cd Signed-off-by: halil.cakal --- .../ForwardedSubscriptionEventCacheConfig.java | 52 ++++++++++ .../avc/ForwardedSubscriptionEventCacheConfig.java | 52 ---------- .../api/impl/event/avc/ResponseTimeoutTask.java | 59 ------------ .../avc/SubscriptionEventResponseConsumer.java | 96 ------------------- .../impl/event/avc/SubscriptionOutcomeMapper.java | 88 ----------------- .../avcsubscription/ResponseTimeoutTask.java | 58 +++++++++++ .../SubscriptionEventForwarder.java | 3 +- .../SubscriptionEventResponseConsumer.java | 95 ++++++++++++++++++ .../SubscriptionEventResponseOutcome.java | 1 - .../avcsubscription/SubscriptionOutcomeMapper.java | 88 +++++++++++++++++ ...orwardedSubscriptionEventCacheConfigSpec.groovy | 77 +++++++++++++++ ...orwardedSubscriptionEventCacheConfigSpec.groovy | 77 --------------- .../SubscriptionEventResponseConsumerSpec.groovy | 85 ----------------- .../event/avc/SubscriptionOutcomeMapperSpec.groovy | 55 ----------- .../SubscriptionEventForwarderSpec.groovy | 6 +- .../SubscriptionEventResponseConsumerSpec.groovy | 106 +++++++++++++++++++++ .../SubscriptionEventResponseOutcomeSpec.groovy | 14 ++- .../SubscriptionOutcomeMapperSpec.groovy | 60 ++++++++++++ 18 files changed, 547 insertions(+), 525 deletions(-) create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfig.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfig.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ResponseTimeoutTask.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapper.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfigSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfigSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapperSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.groovy (limited to 'cps-ncmp-service/src') diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfig.java new file mode 100644 index 0000000000..306d103a8f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfig.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.config.embeddedcache; + +import com.hazelcast.config.MapConfig; +import com.hazelcast.map.IMap; +import java.util.Set; +import org.onap.cps.cache.HazelcastCacheConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Core infrastructure of the hazelcast distributed cache for subscription forward config use cases. + */ +@Configuration +public class ForwardedSubscriptionEventCacheConfig extends HazelcastCacheConfig { + + public static final int SUBSCRIPTION_FORWARD_STARTED_TTL_SECS = 600; + + private static final MapConfig forwardedSubscriptionEventCacheMapConfig = + createMapConfig("forwardedSubscriptionEventCacheMapConfig"); + + /** + * Distributed instance of forwarded subscription information cache that contains subscription event + * id by dmi names as properties. + * + * @return configured map of subscription event ids as keys to sets of dmi names for values + */ + @Bean + public IMap> forwardedSubscriptionEventCache() { + return createHazelcastInstance("hazelCastInstanceSubscriptionEvents", + forwardedSubscriptionEventCacheMapConfig).getMap("forwardedSubscriptionEventCache"); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfig.java deleted file mode 100644 index d2f16a71d4..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfig.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.event.avc; - -import com.hazelcast.config.MapConfig; -import com.hazelcast.map.IMap; -import java.util.Set; -import org.onap.cps.cache.HazelcastCacheConfig; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Core infrastructure of the hazelcast distributed cache for subscription forward config use cases. - */ -@Configuration -public class ForwardedSubscriptionEventCacheConfig extends HazelcastCacheConfig { - - public static final int SUBSCRIPTION_FORWARD_STARTED_TTL_SECS = 600; - - private static final MapConfig forwardedSubscriptionEventCacheMapConfig = - createMapConfig("forwardedSubscriptionEventCacheMapConfig"); - - /** - * Distributed instance of forwarded subscription information cache that contains subscription event - * id by dmi names as properties. - * - * @return configured map of subscription event ids as keys to sets of dmi names for values - */ - @Bean - public IMap> forwardedSubscriptionEventCache() { - return createHazelcastInstance("hazelCastInstanceSubscriptionEvents", - forwardedSubscriptionEventCacheMapConfig).getMap("forwardedSubscriptionEventCache"); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ResponseTimeoutTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ResponseTimeoutTask.java deleted file mode 100644 index 9c7b79f733..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/ResponseTimeoutTask.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.event.avc; - -import com.hazelcast.map.IMap; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.events.avcsubscription.SubscriptionEventResponseOutcome; - -@Slf4j -@RequiredArgsConstructor -public class ResponseTimeoutTask implements Runnable { - - private final IMap> forwardedSubscriptionEventCache; - private final SubscriptionEventResponseOutcome subscriptionEventResponseOutcome; - private final String subscriptionClientId; - private final String subscriptionName; - - @Override - public void run() { - - try { - generateAndSendResponse(); - } catch (final Exception exception) { - log.info("Caught exception in Runnable for ResponseTimeoutTask. StackTrace: {}", - exception.toString()); - } - - } - - private void generateAndSendResponse() { - final String subscriptionEventId = subscriptionClientId + subscriptionName; - if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { - final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); - subscriptionEventResponseOutcome.sendResponse(subscriptionClientId, subscriptionName, - dmiNames.isEmpty()); - forwardedSubscriptionEventCache.remove(subscriptionEventId); - } - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumer.java deleted file mode 100644 index eb3daeb4da..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumer.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.event.avc; - -import com.hazelcast.map.IMap; -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.events.avcsubscription.SubscriptionEventResponseMapper; -import org.onap.cps.ncmp.api.impl.events.avcsubscription.SubscriptionEventResponseOutcome; -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.SubscriptionEventResponse; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@RequiredArgsConstructor -public class SubscriptionEventResponseConsumer { - - private final IMap> forwardedSubscriptionEventCache; - private final SubscriptionPersistence subscriptionPersistence; - private final SubscriptionEventResponseMapper subscriptionEventResponseMapper; - private final SubscriptionEventResponseOutcome subscriptionEventResponseOutcome; - - @Value("${notification.enabled:true}") - private boolean notificationFeatureEnabled; - - @Value("${ncmp.model-loader.subscription:false}") - private boolean subscriptionModelLoaderEnabled; - - /** - * Consume subscription response event. - * - * @param subscriptionEventResponseConsumerRecord the event to be consumed - */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", - properties = {"spring.json.value.default.type=org.onap.cps.ncmp.api.models.SubscriptionEventResponse"}) - public void consumeSubscriptionEventResponse( - final ConsumerRecord subscriptionEventResponseConsumerRecord) { - final SubscriptionEventResponse subscriptionEventResponse = subscriptionEventResponseConsumerRecord.value(); - final String clientId = subscriptionEventResponse.getClientId(); - log.info("subscription event response of clientId: {} is received.", clientId); - final String subscriptionName = subscriptionEventResponse.getSubscriptionName(); - final String subscriptionEventId = clientId + subscriptionName; - boolean isFullOutcomeResponse = false; - if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { - final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); - - dmiNames.remove(subscriptionEventResponse.getDmiName()); - forwardedSubscriptionEventCache.put(subscriptionEventId, dmiNames, - ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); - isFullOutcomeResponse = forwardedSubscriptionEventCache.get(subscriptionEventId).isEmpty(); - - if (isFullOutcomeResponse) { - forwardedSubscriptionEventCache.remove(subscriptionEventId); - } - } - if (subscriptionModelLoaderEnabled) { - updateSubscriptionEvent(subscriptionEventResponse); - } - if (isFullOutcomeResponse && notificationFeatureEnabled) { - subscriptionEventResponseOutcome.sendResponse(clientId, subscriptionName, - isFullOutcomeResponse); - } - } - - private void updateSubscriptionEvent(final SubscriptionEventResponse subscriptionEventResponse) { - final YangModelSubscriptionEvent yangModelSubscriptionEvent = - subscriptionEventResponseMapper - .toYangModelSubscriptionEvent(subscriptionEventResponse); - subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapper.java deleted file mode 100644 index 136c1d6ff4..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapper.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.event.avc; - -import java.util.List; -import java.util.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.SubscriptionEventResponse; -import org.onap.cps.ncmp.events.avc.subscription.v1.SubscriptionEventOutcome; - -@Mapper(componentModel = "spring") -public interface SubscriptionOutcomeMapper { - - @Mapping(source = "clientId", target = "event.subscription.clientID") - @Mapping(source = "subscriptionName", target = "event.subscription.name") - @Mapping(source = "cmHandleIdToStatus", target = "event.predicates.rejectedTargets", - qualifiedByName = "mapStatusToCmHandleRejected") - @Mapping(source = "cmHandleIdToStatus", target = "event.predicates.acceptedTargets", - qualifiedByName = "mapStatusToCmHandleAccepted") - @Mapping(source = "cmHandleIdToStatus", target = "event.predicates.pendingTargets", - qualifiedByName = "mapStatusToCmHandlePending") - SubscriptionEventOutcome toSubscriptionEventOutcome( - SubscriptionEventResponse subscriptionEventResponse); - - /** - * Maps StatusToCMHandle to list of TargetCmHandle rejected. - * - * @param targets as a map - * @return TargetCmHandle list - */ - @Named("mapStatusToCmHandleRejected") - default List mapStatusToCmHandleRejected(Map targets) { - return targets.entrySet() - .stream().filter(target -> SubscriptionStatus.REJECTED.equals(target.getValue())) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - } - - /** - * Maps StatusToCMHandle to list of TargetCmHandle accepted. - * - * @param targets as a map - * @return TargetCmHandle list - */ - @Named("mapStatusToCmHandleAccepted") - default List mapStatusToCmHandleAccepted(Map targets) { - return targets.entrySet() - .stream().filter(target -> SubscriptionStatus.ACCEPTED.equals(target.getValue())) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - } - - /** - * Maps StatusToCMHandle to list of TargetCmHandle pending. - * - * @param targets as a map - * @return TargetCmHandle list - */ - @Named("mapStatusToCmHandlePending") - default List mapStatusToCmHandlePending(Map targets) { - return targets.entrySet() - .stream().filter(target -> SubscriptionStatus.PENDING.equals(target.getValue())) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java new file mode 100644 index 0000000000..a81f8fd731 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/ResponseTimeoutTask.java @@ -0,0 +1,58 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.avcsubscription; + +import com.hazelcast.map.IMap; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +public class ResponseTimeoutTask implements Runnable { + + private final IMap> forwardedSubscriptionEventCache; + private final SubscriptionEventResponseOutcome subscriptionEventResponseOutcome; + private final String subscriptionClientId; + private final String subscriptionName; + + @Override + public void run() { + + try { + generateAndSendResponse(); + } catch (final Exception exception) { + log.info("Caught exception in Runnable for ResponseTimeoutTask. StackTrace: {}", + exception.toString()); + } + + } + + private void generateAndSendResponse() { + final String subscriptionEventId = subscriptionClientId + subscriptionName; + if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { + final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); + subscriptionEventResponseOutcome.sendResponse(subscriptionClientId, subscriptionName, + dmiNames.isEmpty()); + forwardedSubscriptionEventCache.remove(subscriptionEventId); + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java index 19a0f12b0b..9e363f3cdd 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarder.java @@ -35,8 +35,7 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.common.header.Headers; -import org.onap.cps.ncmp.api.impl.event.avc.ForwardedSubscriptionEventCacheConfig; -import org.onap.cps.ncmp.api.impl.event.avc.ResponseTimeoutTask; +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.utils.DmiServiceNameOrganizer; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java new file mode 100644 index 0000000000..a1860a6136 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumer.java @@ -0,0 +1,95 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.avcsubscription; + +import com.hazelcast.map.IMap; +import java.util.Set; +import 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.SubscriptionEventResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class SubscriptionEventResponseConsumer { + + private final IMap> forwardedSubscriptionEventCache; + private final SubscriptionPersistence subscriptionPersistence; + private final SubscriptionEventResponseMapper subscriptionEventResponseMapper; + private final SubscriptionEventResponseOutcome subscriptionEventResponseOutcome; + + @Value("${notification.enabled:true}") + private boolean notificationFeatureEnabled; + + @Value("${ncmp.model-loader.subscription:false}") + private boolean subscriptionModelLoaderEnabled; + + /** + * Consume subscription response event. + * + * @param subscriptionEventResponseConsumerRecord the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", + properties = {"spring.json.value.default.type=org.onap.cps.ncmp.api.models.SubscriptionEventResponse"}) + public void consumeSubscriptionEventResponse( + final ConsumerRecord subscriptionEventResponseConsumerRecord) { + final SubscriptionEventResponse subscriptionEventResponse = subscriptionEventResponseConsumerRecord.value(); + final String clientId = subscriptionEventResponse.getClientId(); + log.info("subscription event response of clientId: {} is received.", clientId); + final String subscriptionName = subscriptionEventResponse.getSubscriptionName(); + final String subscriptionEventId = clientId + subscriptionName; + boolean isFullOutcomeResponse = false; + if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) { + final Set dmiNames = forwardedSubscriptionEventCache.get(subscriptionEventId); + + dmiNames.remove(subscriptionEventResponse.getDmiName()); + forwardedSubscriptionEventCache.put(subscriptionEventId, dmiNames, + ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS); + isFullOutcomeResponse = forwardedSubscriptionEventCache.get(subscriptionEventId).isEmpty(); + + if (isFullOutcomeResponse) { + forwardedSubscriptionEventCache.remove(subscriptionEventId); + } + } + if (subscriptionModelLoaderEnabled) { + updateSubscriptionEvent(subscriptionEventResponse); + } + if (isFullOutcomeResponse && notificationFeatureEnabled) { + subscriptionEventResponseOutcome.sendResponse(clientId, subscriptionName, + isFullOutcomeResponse); + } + } + + private void updateSubscriptionEvent(final SubscriptionEventResponse subscriptionEventResponse) { + final YangModelSubscriptionEvent yangModelSubscriptionEvent = + subscriptionEventResponseMapper + .toYangModelSubscriptionEvent(subscriptionEventResponse); + subscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent); + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java index ade3f22f4b..a74682571b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcome.java @@ -30,7 +30,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.common.header.Headers; import org.apache.kafka.common.header.internals.RecordHeaders; -import org.onap.cps.ncmp.api.impl.event.avc.SubscriptionOutcomeMapper; 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; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java new file mode 100644 index 0000000000..cecde5f816 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapper.java @@ -0,0 +1,88 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.avcsubscription; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus; +import org.onap.cps.ncmp.api.models.SubscriptionEventResponse; +import org.onap.cps.ncmp.events.avc.subscription.v1.SubscriptionEventOutcome; + +@Mapper(componentModel = "spring") +public interface SubscriptionOutcomeMapper { + + @Mapping(source = "clientId", target = "event.subscription.clientID") + @Mapping(source = "subscriptionName", target = "event.subscription.name") + @Mapping(source = "cmHandleIdToStatus", target = "event.predicates.rejectedTargets", + qualifiedByName = "mapStatusToCmHandleRejected") + @Mapping(source = "cmHandleIdToStatus", target = "event.predicates.acceptedTargets", + qualifiedByName = "mapStatusToCmHandleAccepted") + @Mapping(source = "cmHandleIdToStatus", target = "event.predicates.pendingTargets", + qualifiedByName = "mapStatusToCmHandlePending") + SubscriptionEventOutcome toSubscriptionEventOutcome( + SubscriptionEventResponse subscriptionEventResponse); + + /** + * Maps StatusToCMHandle to list of TargetCmHandle rejected. + * + * @param targets as a map + * @return TargetCmHandle list + */ + @Named("mapStatusToCmHandleRejected") + default List mapStatusToCmHandleRejected(Map targets) { + return targets.entrySet() + .stream().filter(target -> SubscriptionStatus.REJECTED.equals(target.getValue())) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + } + + /** + * Maps StatusToCMHandle to list of TargetCmHandle accepted. + * + * @param targets as a map + * @return TargetCmHandle list + */ + @Named("mapStatusToCmHandleAccepted") + default List mapStatusToCmHandleAccepted(Map targets) { + return targets.entrySet() + .stream().filter(target -> SubscriptionStatus.ACCEPTED.equals(target.getValue())) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + } + + /** + * Maps StatusToCMHandle to list of TargetCmHandle pending. + * + * @param targets as a map + * @return TargetCmHandle list + */ + @Named("mapStatusToCmHandlePending") + default List mapStatusToCmHandlePending(Map targets) { + return targets.entrySet() + .stream().filter(target -> SubscriptionStatus.PENDING.equals(target.getValue())) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfigSpec.groovy new file mode 100644 index 0000000000..879525e572 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ForwardedSubscriptionEventCacheConfigSpec.groovy @@ -0,0 +1,77 @@ +/* + * ============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.config.embeddedcache + +import com.hazelcast.config.Config +import com.hazelcast.core.Hazelcast +import com.hazelcast.map.IMap +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest(classes = [ForwardedSubscriptionEventCacheConfig]) +class ForwardedSubscriptionEventCacheConfigSpec extends Specification { + + @Autowired + private IMap> forwardedSubscriptionEventCache + + def 'Embedded (hazelcast) cache for Forwarded Subscription Event Cache.'() { + expect: 'system is able to create an instance of the Forwarded Subscription Event Cache' + assert null != forwardedSubscriptionEventCache + and: 'there is at least 1 instance' + assert Hazelcast.allHazelcastInstances.size() > 0 + and: 'Forwarded Subscription Event Cache is present' + assert Hazelcast.allHazelcastInstances.name.contains('hazelCastInstanceSubscriptionEvents') + } + + def 'Verify configs for Distributed Caches'(){ + given: 'the Forwarded Subscription Event Cache config' + def forwardedSubscriptionEventCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelCastInstanceSubscriptionEvents').config + def forwardedSubscriptionEventCacheMapConfig = forwardedSubscriptionEventCacheConfig.mapConfigs.get('forwardedSubscriptionEventCacheMapConfig') + expect: 'system created instance with correct config' + assert forwardedSubscriptionEventCacheConfig.clusterName == 'cps-and-ncmp-test-caches' + assert forwardedSubscriptionEventCacheMapConfig.backupCount == 3 + assert forwardedSubscriptionEventCacheMapConfig.asyncBackupCount == 3 + } + + def 'Verify deployment network configs for Distributed Caches'() { + given: 'the Forwarded Subscription Event Cache config' + def forwardedSubscriptionEventCacheNetworkConfig = Hazelcast.getHazelcastInstanceByName('hazelCastInstanceSubscriptionEvents').config.networkConfig + expect: 'system created instance with correct config' + assert forwardedSubscriptionEventCacheNetworkConfig.join.autoDetectionConfig.enabled + assert !forwardedSubscriptionEventCacheNetworkConfig.join.kubernetesConfig.enabled + } + + def 'Verify network config'() { + given: 'Synchronization config object and test configuration' + def objectUnderTest = new ForwardedSubscriptionEventCacheConfig() + def testConfig = new Config() + when: 'kubernetes properties are enabled' + objectUnderTest.cacheKubernetesEnabled = true + objectUnderTest.cacheKubernetesServiceName = 'test-service-name' + and: 'method called to update the discovery mode' + objectUnderTest.updateDiscoveryMode(testConfig) + then: 'applied properties are reflected' + assert testConfig.networkConfig.join.kubernetesConfig.enabled + assert testConfig.networkConfig.join.kubernetesConfig.properties.get('service-name') == 'test-service-name' + + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfigSpec.groovy deleted file mode 100644 index 03d3a1c105..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfigSpec.groovy +++ /dev/null @@ -1,77 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.event.avc - -import com.hazelcast.config.Config -import com.hazelcast.core.Hazelcast -import com.hazelcast.map.IMap -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - -@SpringBootTest(classes = [ForwardedSubscriptionEventCacheConfig]) -class ForwardedSubscriptionEventCacheConfigSpec extends Specification { - - @Autowired - private IMap> forwardedSubscriptionEventCache - - def 'Embedded (hazelcast) cache for Forwarded Subscription Event Cache.'() { - expect: 'system is able to create an instance of the Forwarded Subscription Event Cache' - assert null != forwardedSubscriptionEventCache - and: 'there is at least 1 instance' - assert Hazelcast.allHazelcastInstances.size() > 0 - and: 'Forwarded Subscription Event Cache is present' - assert Hazelcast.allHazelcastInstances.name.contains('hazelCastInstanceSubscriptionEvents') - } - - def 'Verify configs for Distributed Caches'(){ - given: 'the Forwarded Subscription Event Cache config' - def forwardedSubscriptionEventCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelCastInstanceSubscriptionEvents').config - def forwardedSubscriptionEventCacheMapConfig = forwardedSubscriptionEventCacheConfig.mapConfigs.get('forwardedSubscriptionEventCacheMapConfig') - expect: 'system created instance with correct config' - assert forwardedSubscriptionEventCacheConfig.clusterName == 'cps-and-ncmp-test-caches' - assert forwardedSubscriptionEventCacheMapConfig.backupCount == 3 - assert forwardedSubscriptionEventCacheMapConfig.asyncBackupCount == 3 - } - - def 'Verify deployment network configs for Distributed Caches'() { - given: 'the Forwarded Subscription Event Cache config' - def forwardedSubscriptionEventCacheNetworkConfig = Hazelcast.getHazelcastInstanceByName('hazelCastInstanceSubscriptionEvents').config.networkConfig - expect: 'system created instance with correct config' - assert forwardedSubscriptionEventCacheNetworkConfig.join.autoDetectionConfig.enabled - assert !forwardedSubscriptionEventCacheNetworkConfig.join.kubernetesConfig.enabled - } - - def 'Verify network config'() { - given: 'Synchronization config object and test configuration' - def objectUnderTest = new ForwardedSubscriptionEventCacheConfig() - def testConfig = new Config() - when: 'kubernetes properties are enabled' - objectUnderTest.cacheKubernetesEnabled = true - objectUnderTest.cacheKubernetesServiceName = 'test-service-name' - and: 'method called to update the discovery mode' - objectUnderTest.updateDiscoveryMode(testConfig) - then: 'applied properties are reflected' - assert testConfig.networkConfig.join.kubernetesConfig.enabled - assert testConfig.networkConfig.join.kubernetesConfig.properties.get('service-name') == 'test-service-name' - - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumerSpec.groovy deleted file mode 100644 index 80c9b69c0b..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumerSpec.groovy +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.event.avc - -import com.fasterxml.jackson.databind.ObjectMapper -import com.hazelcast.map.IMap -import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.api.impl.events.avcsubscription.SubscriptionEventResponseMapper -import org.onap.cps.ncmp.api.impl.events.avcsubscription.SubscriptionEventResponseOutcome -import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistenceImpl -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.api.models.SubscriptionEventResponse -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class SubscriptionEventResponseConsumerSpec extends MessagingBaseSpec { - - IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) - def mockSubscriptionPersistence = Mock(SubscriptionPersistenceImpl) - def mockSubscriptionEventResponseMapper = Mock(SubscriptionEventResponseMapper) - def mockSubscriptionEventResponseOutcome = Mock(SubscriptionEventResponseOutcome) - - def objectUnderTest = new SubscriptionEventResponseConsumer(mockForwardedSubscriptionEventCache, - mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockSubscriptionEventResponseOutcome) - - def cmHandleToStatusMap = [CMHandle1: 'PENDING', CMHandle2: 'ACCEPTED'] as Map - def testEventReceived = new SubscriptionEventResponse(clientId: 'some-client-id', - subscriptionName: 'some-subscription-name', dmiName: 'some-dmi-name', cmHandleIdToStatus: cmHandleToStatusMap) - def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testEventReceived) - - def 'Consume Subscription Event Response where all DMIs have responded'() { - given: 'a subscription event response and notifications are enabled' - objectUnderTest.notificationFeatureEnabled = true - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = true - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEventResponse(consumerRecord) - then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' - 1 * mockForwardedSubscriptionEventCache.containsKey('some-client-idsome-subscription-name') >> true - 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['some-dmi-name'] as Set) - and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' - 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> ([] as Set) - and: 'the subscription event is removed from the map' - 1 * mockForwardedSubscriptionEventCache.remove('some-client-idsome-subscription-name') - and: 'a response outcome has been created' - 1 * mockSubscriptionEventResponseOutcome.sendResponse('some-client-id', 'some-subscription-name', true) - } - - def 'Consume Subscription Event Response where another DMI has not yet responded'() { - given: 'a subscription event response and notifications are enabled' - objectUnderTest.notificationFeatureEnabled = true - and: 'subscription model loader is enabled' - objectUnderTest.subscriptionModelLoaderEnabled = true - when: 'the valid event is consumed' - objectUnderTest.consumeSubscriptionEventResponse(consumerRecord) - then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' - 1 * mockForwardedSubscriptionEventCache.containsKey('some-client-idsome-subscription-name') >> true - 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['some-dmi-name', 'non-responded-dmi'] as Set) - and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' - 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['non-responded-dmi'] as Set) - and: 'the subscription event is not removed from the map' - 0 * mockForwardedSubscriptionEventCache.remove(_) - and: 'a response outcome has not been created' - 0 * mockSubscriptionEventResponseOutcome.sendResponse(*_) - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapperSpec.groovy deleted file mode 100644 index 22067745f0..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionOutcomeMapperSpec.groovy +++ /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.event.avc - -import com.fasterxml.jackson.databind.ObjectMapper -import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.models.SubscriptionEventResponse -import org.onap.cps.ncmp.events.avc.subscription.v1.SubscriptionEventOutcome -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 SubscriptionOutcomeMapperSpec extends Specification { - - SubscriptionOutcomeMapper objectUnderTest = Mappers.getMapper(SubscriptionOutcomeMapper) - - @Autowired - JsonObjectMapper jsonObjectMapper - - def 'Map subscription event response to subscription event outcome'() { - given: 'a Subscription Response Event' - def jsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') - def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEventResponse.class) - and: 'a Subscription Outcome Event' - def jsonDataOutcome = TestUtils.getResourceFileContent('avcSubscriptionOutcomeEvent.json') - def testEventTarget = jsonObjectMapper.convertJsonString(jsonDataOutcome, SubscriptionEventOutcome.class) - when: 'the subscription response event is mapped to a subscription event outcome' - def result = objectUnderTest.toSubscriptionEventOutcome(testEventToMap) - result.setEventType(SubscriptionEventOutcome.EventType.PARTIAL_OUTCOME) - then: 'the resulting subscription event outcome contains the correct clientId' - assert result == testEventTarget - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy index 63ddcef554..a9eaaee916 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy @@ -137,14 +137,14 @@ class SubscriptionEventForwarderSpec extends MessagingBaseSpec { 0 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1", "DMIName2"] as Set) and: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' 0 * mockSubscriptionEventPublisher.publishEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", - subscriptionEvent -> { + consumerRecord.headers(),subscriptionEvent -> { Map targets = subscriptionEvent.getEvent().getPredicates().getTargets().get(0) targets["CMHandle1"] == ["shape":"circle"] targets["CMHandle2"] == ["shape":"square"] } ) 0 * mockSubscriptionEventPublisher.publishEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2", - subscriptionEvent -> { + consumerRecord.headers(),subscriptionEvent -> { Map targets = subscriptionEvent.getEvent().getPredicates().getTargets().get(0) targets["CMHandle3"] == ["shape":"triangle"] } @@ -154,6 +154,8 @@ class SubscriptionEventForwarderSpec extends MessagingBaseSpec { 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: 'subscription outcome has been sent' + 1 * mockSubscriptionEventResponseOutcome.sendResponse('SCO-9989752', 'cm-subscription-001', true) } static def createYangModelCmHandleWithDmiProperty(id, dmiId,propertyName, propertyValue) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy new file mode 100644 index 0000000000..26bb7e78ee --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseConsumerSpec.groovy @@ -0,0 +1,106 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.events.avcsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import com.hazelcast.map.IMap +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.api.models.SubscriptionEventResponse +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class SubscriptionEventResponseConsumerSpec extends MessagingBaseSpec { + + IMap> mockForwardedSubscriptionEventCache = Mock(IMap>) + def mockSubscriptionPersistence = Mock(SubscriptionPersistenceImpl) + def mockSubscriptionEventResponseMapper = Mock(SubscriptionEventResponseMapper) + def mockSubscriptionEventResponseOutcome = Mock(SubscriptionEventResponseOutcome) + + def objectUnderTest = new SubscriptionEventResponseConsumer(mockForwardedSubscriptionEventCache, + mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockSubscriptionEventResponseOutcome) + + def cmHandleToStatusMap = [CMHandle1: 'PENDING', CMHandle2: 'ACCEPTED'] as Map + def testEventReceived = new SubscriptionEventResponse(clientId: 'some-client-id', + subscriptionName: 'some-subscription-name', dmiName: 'some-dmi-name', cmHandleIdToStatus: cmHandleToStatusMap) + def consumerRecord = new ConsumerRecord('topic-name', 0, 0, 'event-key', testEventReceived) + + def 'Consume Subscription Event Response where all DMIs have responded'() { + given: 'a subscription event response and notifications are enabled' + objectUnderTest.notificationFeatureEnabled = isNotificationFeatureEnabled + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = true + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEventResponse(consumerRecord) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('some-client-idsome-subscription-name') >> true + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['some-dmi-name'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> ([] as Set) + and: 'the subscription event is removed from the map' + 1 * mockForwardedSubscriptionEventCache.remove('some-client-idsome-subscription-name') + and: 'a response outcome has been created' + numberOfExpectedCallToSendResponse * mockSubscriptionEventResponseOutcome.sendResponse('some-client-id', 'some-subscription-name', isFullOutcomeResponse) + where: 'the following values are used' + scenario | isNotificationFeatureEnabled | isFullOutcomeResponse || numberOfExpectedCallToSendResponse + 'Response sent' | true | true || 1 + 'Response not sent' | true | false || 0 + 'Response not sent' | false | true || 0 + 'Response not sent' | false | false || 0 + } + + def 'Consume Subscription Event Response where another DMI has not yet responded'() { + given: 'a subscription event response and notifications are enabled' + objectUnderTest.notificationFeatureEnabled = true + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = true + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEventResponse(consumerRecord) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('some-client-idsome-subscription-name') >> true + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['some-dmi-name', 'non-responded-dmi'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['non-responded-dmi'] as Set) + and: 'the subscription event is not removed from the map' + 0 * mockForwardedSubscriptionEventCache.remove(_) + and: 'a response outcome has not been created' + 0 * mockSubscriptionEventResponseOutcome.sendResponse(*_) + } + + def 'Update subscription event when the model loader flag is enabled'() { + given: 'subscription model loader is enabled as per #scenario' + objectUnderTest.subscriptionModelLoaderEnabled = isSubscriptionModelLoaderEnabled + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEventResponse(consumerRecord) + then: 'the forwarded subscription event cache does not return dmiName for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('some-client-idsome-subscription-name') >> false + and: 'the mapper returns yang model subscription event with #numberOfExpectedCall' + numberOfExpectedCall * mockSubscriptionEventResponseMapper.toYangModelSubscriptionEvent(_) + and: 'subscription event has been updated into DB with #numberOfExpectedCall' + numberOfExpectedCall * mockSubscriptionPersistence.saveSubscriptionEvent(_) + where: 'the following values are used' + scenario | isSubscriptionModelLoaderEnabled || numberOfExpectedCall + 'The event is updated' | true || 1 + 'The event is not updated' | false || 0 + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy index 53c5cd2c7b..3570a9e366 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventResponseOutcomeSpec.groovy @@ -22,7 +22,6 @@ package org.onap.cps.ncmp.api.impl.events.avcsubscription import com.fasterxml.jackson.databind.ObjectMapper import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.event.avc.SubscriptionOutcomeMapper 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 @@ -32,7 +31,6 @@ import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest -import org.testcontainers.shaded.org.bouncycastle.crypto.engines.EthereumIESEngine @SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, SubscriptionOutcomeMapper, SubscriptionEventResponseOutcome]) class SubscriptionEventResponseOutcomeSpec extends DataNodeBaseSpec { @@ -56,14 +54,14 @@ class SubscriptionEventResponseOutcomeSpec extends DataNodeBaseSpec { when: 'a response is generated' def result = objectUnderTest.generateResponse('some-client-id', 'some-subscription-name', isFullOutcomeResponse) then: 'the result will have the same values as same as in dataNode4' - result.eventType == eventType + result.eventType == expectedEventType result.getEvent().getSubscription().getClientID() == 'some-client-id' result.getEvent().getSubscription().getName() == 'some-subscription-name' result.getEvent().getPredicates().getPendingTargets() == ['CMHandle3'] result.getEvent().getPredicates().getRejectedTargets() == ['CMHandle1'] result.getEvent().getPredicates().getAcceptedTargets() == ['CMHandle2'] where: 'the following values are used' - scenario | isFullOutcomeResponse || eventType + scenario | isFullOutcomeResponse || expectedEventType 'is full outcome' | true || SubscriptionEventOutcome.EventType.COMPLETE_OUTCOME 'is partial outcome' | false || SubscriptionEventOutcome.EventType.PARTIAL_OUTCOME } @@ -74,7 +72,7 @@ class SubscriptionEventResponseOutcomeSpec extends DataNodeBaseSpec { and: 'an outcome event' def jsonData = TestUtils.getResourceFileContent('avcSubscriptionOutcomeEvent.json') def eventOutcome = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEventOutcome.class) - eventOutcome.setEventType(eventType) + eventOutcome.setEventType(expectedEventType) when: 'a subscription outcome message formed' def result = objectUnderTest.formSubscriptionOutcomeMessage(cmHandleIdToStatus, 'SCO-9989752', 'cm-subscription-001', isFullOutcomeResponse) @@ -82,8 +80,8 @@ class SubscriptionEventResponseOutcomeSpec extends DataNodeBaseSpec { then: 'the result will be equal to event outcome' result == eventOutcome where: 'the following values are used' - scenario | isFullOutcomeResponse | eventType - 'is full outcome' | true | SubscriptionEventOutcome.EventType.COMPLETE_OUTCOME - 'is partial outcome' | false | SubscriptionEventOutcome.EventType.PARTIAL_OUTCOME + scenario | isFullOutcomeResponse || expectedEventType + 'is full outcome' | true || SubscriptionEventOutcome.EventType.COMPLETE_OUTCOME + 'is partial outcome' | false || SubscriptionEventOutcome.EventType.PARTIAL_OUTCOME } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.groovy new file mode 100644 index 0000000000..b05e983c03 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionOutcomeMapperSpec.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.avcsubscription + +import com.fasterxml.jackson.databind.ObjectMapper +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.models.SubscriptionEventResponse +import org.onap.cps.ncmp.events.avc.subscription.v1.SubscriptionEventOutcome +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 SubscriptionOutcomeMapperSpec extends Specification { + + SubscriptionOutcomeMapper objectUnderTest = Mappers.getMapper(SubscriptionOutcomeMapper) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def 'Map subscription event response to subscription event outcome'() { + given: 'a Subscription Response Event' + def subscriptionResponseJsonData = TestUtils.getResourceFileContent('avcSubscriptionEventResponse.json') + def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, SubscriptionEventResponse.class) + and: 'a Subscription Outcome Event' + def jsonDataOutcome = TestUtils.getResourceFileContent('avcSubscriptionOutcomeEvent.json') + def expectedEventOutcome = jsonObjectMapper.convertJsonString(jsonDataOutcome, SubscriptionEventOutcome.class) + expectedEventOutcome.setEventType(expectedEventType) + when: 'the subscription response event is mapped to a subscription event outcome' + def result = objectUnderTest.toSubscriptionEventOutcome(subscriptionResponseEvent) + result.setEventType(expectedEventType) + then: 'the resulting subscription event outcome contains the correct clientId' + assert result == expectedEventOutcome + where: 'the following values are used' + scenario || expectedEventType + 'is full outcome' || SubscriptionEventOutcome.EventType.COMPLETE_OUTCOME + 'is partial outcome' || SubscriptionEventOutcome.EventType.PARTIAL_OUTCOME + } +} \ No newline at end of file -- cgit 1.2.3-korg