summaryrefslogtreecommitdiffstats
path: root/cps-ncmp-service/src
diff options
context:
space:
mode:
Diffstat (limited to 'cps-ncmp-service/src')
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java10
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.java)50
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java26
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java57
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java10
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionEvent.java50
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java45
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy38
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy10
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec.groovy)62
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy59
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy48
-rw-r--r--cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json10
-rw-r--r--cps-ncmp-service/src/test/resources/cmSubscriptionEvent.json31
-rw-r--r--cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json8
15 files changed, 319 insertions, 195 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java
index 1ac4044114..9459778fd7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumer.java
@@ -36,6 +36,7 @@ import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence;
import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus;
import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent;
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent;
import org.onap.cps.spi.model.DataNode;
import org.springframework.beans.factory.annotation.Value;
@@ -66,7 +67,7 @@ public class CmSubscriptionDmiOutEventConsumer {
*/
@KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}",
containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory")
- public void consumeSubscriptionEventResponse(
+ public void consumeDmiOutEvent(
final ConsumerRecord<String, CloudEvent> cmSubscriptionDmiOutConsumerRecord) {
final CloudEvent cloudEvent = cmSubscriptionDmiOutConsumerRecord.value();
final String eventType = cmSubscriptionDmiOutConsumerRecord.value().getType();
@@ -90,7 +91,12 @@ public class CmSubscriptionDmiOutEventConsumer {
if (createOutcomeResponse
&& notificationFeatureEnabled
&& hasNoPendingCmHandles(clientId, subscriptionName)) {
- cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionDmiOutEvent, eventType);
+
+ final CmSubscriptionEvent cmSubscriptionEvent = new CmSubscriptionEvent();
+ cmSubscriptionEvent.setClientId(cmSubscriptionDmiOutEvent.getData().getClientId());
+ cmSubscriptionEvent.setSubscriptionName(cmSubscriptionDmiOutEvent.getData().getSubscriptionName());
+
+ cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent, eventType);
forwardedSubscriptionEventCache.remove(subscriptionEventId);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java
index 99452c6c24..0fe2c9ae5d 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.java
@@ -26,43 +26,43 @@ import java.util.stream.Collectors;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent;
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus;
+import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus;
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent;
+import org.onap.cps.ncmp.api.models.CmSubscriptionStatus;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfo;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.AdditionalInfoDetail;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent;
import org.onap.cps.spi.exceptions.DataValidationException;
@Mapper(componentModel = "spring")
-public interface CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper {
+public interface CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper {
- @Mapping(source = "data.subscriptionStatus", target = "data.additionalInfo",
- qualifiedByName = "mapListOfSubscriptionStatusToAdditionalInfo")
- CmSubscriptionNcmpOutEvent toCmSubscriptionNcmpOutEvent(CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent);
+ @Mapping(source = "cmSubscriptionStatus", target = "data.additionalInfo",
+ qualifiedByName = "mapCmSubscriptionStatusToAdditionalInfo")
+ CmSubscriptionNcmpOutEvent toCmSubscriptionNcmpOutEvent(CmSubscriptionEvent cmSubscriptionEvent);
/**
* Maps list of SubscriptionStatus to an AdditionalInfo.
*
- * @param subscriptionStatusList containing details
+ * @param cmSubscriptionStatusList containing details
* @return an AdditionalInfo
*/
- @Named("mapListOfSubscriptionStatusToAdditionalInfo")
- default AdditionalInfo mapListOfSubscriptionStatusToAdditionalInfo(
- final List<SubscriptionStatus> subscriptionStatusList) {
- if (subscriptionStatusList == null || subscriptionStatusList.isEmpty()) {
- throw new DataValidationException("Invalid subscriptionStatusList",
- "SubscriptionStatus list cannot be null or empty");
+ @Named("mapCmSubscriptionStatusToAdditionalInfo")
+ default AdditionalInfo mapCmSubscriptionStatusToAdditionalInfo(
+ final List<CmSubscriptionStatus> cmSubscriptionStatusList) {
+ if (cmSubscriptionStatusList == null || cmSubscriptionStatusList.isEmpty()) {
+ throw new DataValidationException("Invalid cmSubscriptionStatusList",
+ "CmSubscriptionStatus list cannot be null or empty");
}
- final Map<String, List<SubscriptionStatus>> rejectedSubscriptionsPerDetails = getSubscriptionsPerDetails(
- subscriptionStatusList, SubscriptionStatus.Status.REJECTED);
+ final Map<String, List<CmSubscriptionStatus>> rejectedSubscriptionsPerDetails =
+ getSubscriptionsPerDetails(cmSubscriptionStatusList, SubscriptionStatus.REJECTED);
final Map<String, List<String>> rejectedCmHandlesPerDetails =
getCmHandlesPerDetails(rejectedSubscriptionsPerDetails);
final List<AdditionalInfoDetail> rejectedCmHandles = getAdditionalInfoDetailList(rejectedCmHandlesPerDetails);
-
- final Map<String, List<SubscriptionStatus>> pendingSubscriptionsPerDetails = getSubscriptionsPerDetails(
- subscriptionStatusList, SubscriptionStatus.Status.PENDING);
+ final Map<String, List<CmSubscriptionStatus>> pendingSubscriptionsPerDetails =
+ getSubscriptionsPerDetails(cmSubscriptionStatusList, SubscriptionStatus.PENDING);
final Map<String, List<String>> pendingCmHandlesPerDetails =
getCmHandlesPerDetails(pendingSubscriptionsPerDetails);
final List<AdditionalInfoDetail> pendingCmHandles = getAdditionalInfoDetailList(pendingCmHandlesPerDetails);
@@ -74,20 +74,20 @@ public interface CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper {
return additionalInfo;
}
- private static Map<String, List<SubscriptionStatus>> getSubscriptionsPerDetails(
- final List<SubscriptionStatus> subscriptionStatusList, final SubscriptionStatus.Status status) {
- return subscriptionStatusList.stream()
+ private static Map<String, List<CmSubscriptionStatus>> getSubscriptionsPerDetails(
+ final List<CmSubscriptionStatus> cmSubscriptionStatusList, final SubscriptionStatus status) {
+ return cmSubscriptionStatusList.stream()
.filter(subscriptionStatus -> subscriptionStatus.getStatus() == status)
- .collect(Collectors.groupingBy(SubscriptionStatus::getDetails));
+ .collect(Collectors.groupingBy(CmSubscriptionStatus::getDetails));
}
private static Map<String, List<String>> getCmHandlesPerDetails(
- final Map<String, List<SubscriptionStatus>> subscriptionsPerDetails) {
- return subscriptionsPerDetails.entrySet().stream()
+ final Map<String, List<CmSubscriptionStatus>> cmSubscriptionsPerDetails) {
+ return cmSubscriptionsPerDetails.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
- .map(SubscriptionStatus::getId)
+ .map(CmSubscriptionStatus::getId)
.collect(Collectors.toList())
));
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java
index 4a174954ea..ea2d17d3a7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java
@@ -43,9 +43,8 @@ import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent;
import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent;
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent;
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.Data;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent;
import org.springframework.beans.factory.annotation.Value;
@@ -97,12 +96,11 @@ public class CmSubscriptionNcmpInEventForwarder {
private void findDmisAndRespond(final CmSubscriptionNcmpInEvent cmSubscriptionNcmpInEvent, final String eventType,
final List<String> cmHandleTargetsAsStrings,
final Map<String, Map<String, Map<String, String>>> dmiPropertiesPerCmHandleIdPerServiceName) {
- final CmSubscriptionDmiOutEvent emptyCmSubscriptionDmiOutEvent =
- new CmSubscriptionDmiOutEvent().withData(new Data());
- emptyCmSubscriptionDmiOutEvent.getData()
- .setSubscriptionName(cmSubscriptionNcmpInEvent.getData().getSubscription().getName());
- emptyCmSubscriptionDmiOutEvent.getData()
- .setClientId(cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID());
+
+ final CmSubscriptionEvent cmSubscriptionEvent = new CmSubscriptionEvent();
+ cmSubscriptionEvent.setSubscriptionName(cmSubscriptionNcmpInEvent.getData().getSubscription().getName());
+ cmSubscriptionEvent.setClientId(cmSubscriptionNcmpInEvent.getData().getSubscription().getClientID());
+
final List<String> cmHandlesThatExistsInDb =
dmiPropertiesPerCmHandleIdPerServiceName.entrySet().stream().map(Map.Entry::getValue).map(Map::keySet)
.flatMap(Set::stream).collect(Collectors.toList());
@@ -117,10 +115,10 @@ public class CmSubscriptionNcmpInEventForwarder {
targetCmHandlesDoesNotExistInDb);
}
if (dmisToRespond.isEmpty()) {
- cmSubscriptionNcmpOutEventPublisher.sendResponse(emptyCmSubscriptionDmiOutEvent,
+ cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent,
"subscriptionCreatedStatus");
} else {
- startResponseTimeout(emptyCmSubscriptionDmiOutEvent, dmisToRespond);
+ startResponseTimeout(cmSubscriptionEvent, dmisToRespond);
final CmSubscriptionDmiInEvent cmSubscriptionDmiInEvent =
cmSubscriptionNcmpInEventToCmSubscriptionDmiInEventMapper.toCmSubscriptionDmiInEvent(
cmSubscriptionNcmpInEvent);
@@ -128,17 +126,17 @@ public class CmSubscriptionNcmpInEventForwarder {
}
}
- private void startResponseTimeout(final CmSubscriptionDmiOutEvent emptyCmSubscriptionDmiOutEvent,
+ private void startResponseTimeout(final CmSubscriptionEvent cmSubscriptionEvent,
final Set<String> dmisToRespond) {
- final String subscriptionClientId = emptyCmSubscriptionDmiOutEvent.getData().getClientId();
- final String subscriptionName = emptyCmSubscriptionDmiOutEvent.getData().getSubscriptionName();
+ final String subscriptionClientId = cmSubscriptionEvent.getClientId();
+ final String subscriptionName = cmSubscriptionEvent.getSubscriptionName();
final String subscriptionEventId = subscriptionClientId + subscriptionName;
forwardedSubscriptionEventCache.put(subscriptionEventId, dmisToRespond,
ForwardedSubscriptionEventCacheConfig.SUBSCRIPTION_FORWARD_STARTED_TTL_SECS, TimeUnit.SECONDS);
final ResponseTimeoutTask responseTimeoutTask =
new ResponseTimeoutTask(forwardedSubscriptionEventCache, cmSubscriptionNcmpOutEventPublisher,
- emptyCmSubscriptionDmiOutEvent);
+ cmSubscriptionEvent);
executorService.schedule(responseTimeoutTask, dmiResponseTimeoutInMs, TimeUnit.MILLISECONDS);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java
index 38cc724be0..473538c93e 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java
@@ -32,7 +32,8 @@ import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence;
import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus;
import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper;
import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper;
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent;
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent;
+import org.onap.cps.ncmp.api.models.CmSubscriptionStatus;
import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -46,8 +47,8 @@ public class CmSubscriptionNcmpOutEventPublisher {
private final EventsPublisher<CloudEvent> outcomeEventsPublisher;
- private final CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper
- cmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper;
+ private final CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper
+ cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper;
private final SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper;
@@ -57,54 +58,48 @@ public class CmSubscriptionNcmpOutEventPublisher {
/**
* This is for construction of outcome message to be published for client apps.
*
- * @param cmSubscriptionDmiOutEvent event produced by Dmi Plugin
+ * @param cmSubscriptionEvent event produced by Dmi Plugin
*/
- public void sendResponse(final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent, final String eventKey) {
+ public void sendResponse(final CmSubscriptionEvent cmSubscriptionEvent, final String eventType) {
final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent =
- formCmSubscriptionNcmpOutEvent(cmSubscriptionDmiOutEvent);
- final String subscriptionClientId = cmSubscriptionDmiOutEvent.getData().getClientId();
- final String subscriptionName = cmSubscriptionDmiOutEvent.getData().getSubscriptionName();
+ formCmSubscriptionNcmpOutEvent(cmSubscriptionEvent);
+ final String subscriptionClientId = cmSubscriptionEvent.getClientId();
+ final String subscriptionName = cmSubscriptionEvent.getSubscriptionName();
final String subscriptionEventId = subscriptionClientId + subscriptionName;
final CloudEvent subscriptionOutcomeCloudEvent =
subscriptionOutcomeCloudMapper.toCloudEvent(cmSubscriptionNcmpOutEvent,
- subscriptionEventId, eventKey);
+ subscriptionEventId, eventType);
outcomeEventsPublisher.publishCloudEvent(subscriptionOutcomeEventTopic,
subscriptionEventId, subscriptionOutcomeCloudEvent);
}
private CmSubscriptionNcmpOutEvent formCmSubscriptionNcmpOutEvent(
- final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent) {
+ final CmSubscriptionEvent cmSubscriptionEvent) {
final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMap =
DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode(
subscriptionPersistence.getCmHandlesForSubscriptionEvent(
- cmSubscriptionDmiOutEvent.getData().getClientId(),
- cmSubscriptionDmiOutEvent.getData().getSubscriptionName()));
- final List<org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus>
- subscriptionStatusList =
+ cmSubscriptionEvent.getClientId(),
+ cmSubscriptionEvent.getSubscriptionName()));
+ final List<CmSubscriptionStatus> cmSubscriptionStatusList =
mapCmHandleIdStatusDetailsMapToSubscriptionStatusList(cmHandleIdToStatusAndDetailsAsMap);
- cmSubscriptionDmiOutEvent.getData().setSubscriptionStatus(subscriptionStatusList);
- return fromDmiOutEvent(cmSubscriptionDmiOutEvent,
+ cmSubscriptionEvent.setCmSubscriptionStatus(cmSubscriptionStatusList);
+ return fromCmSubscriptionEvent(cmSubscriptionEvent,
decideOnNcmpEventResponseCodeForSubscription(cmHandleIdToStatusAndDetailsAsMap));
}
- private static List<org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus>
- mapCmHandleIdStatusDetailsMapToSubscriptionStatusList(
+ private static List<CmSubscriptionStatus> mapCmHandleIdStatusDetailsMapToSubscriptionStatusList(
final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMap) {
return cmHandleIdToStatusAndDetailsAsMap.entrySet()
.stream().map(entryset -> {
- final org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus
- subscriptionStatus = new org.onap.cps.ncmp.events.cmsubscription1_0_0
- .dmi_to_ncmp.SubscriptionStatus();
+ final CmSubscriptionStatus cmSubscriptionStatus = new CmSubscriptionStatus();
final String cmHandleId = entryset.getKey();
final Map<String, String> statusAndDetailsMap = entryset.getValue();
final String status = statusAndDetailsMap.get("status");
final String details = statusAndDetailsMap.get("details");
- subscriptionStatus.setId(cmHandleId);
- subscriptionStatus.setStatus(
- org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp
- .SubscriptionStatus.Status.fromValue(status));
- subscriptionStatus.setDetails(details);
- return subscriptionStatus;
+ cmSubscriptionStatus.setId(cmHandleId);
+ cmSubscriptionStatus.setStatus(SubscriptionStatus.fromString(status));
+ cmSubscriptionStatus.setDetails(details);
+ return cmSubscriptionStatus;
}).collect(Collectors.toList());
}
@@ -138,13 +133,13 @@ public class CmSubscriptionNcmpOutEventPublisher {
.allMatch(entryset -> entryset.containsValue(subscriptionStatus.toString()));
}
- private CmSubscriptionNcmpOutEvent fromDmiOutEvent(
- final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent,
+ private CmSubscriptionNcmpOutEvent fromCmSubscriptionEvent(
+ final CmSubscriptionEvent cmSubscriptionEvent,
final NcmpEventResponseCode ncmpEventResponseCode) {
final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent =
- cmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper.toCmSubscriptionNcmpOutEvent(
- cmSubscriptionDmiOutEvent);
+ cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.toCmSubscriptionNcmpOutEvent(
+ cmSubscriptionEvent);
cmSubscriptionNcmpOutEvent.getData().setStatusCode(Integer.parseInt(ncmpEventResponseCode.getStatusCode()));
cmSubscriptionNcmpOutEvent.getData().setStatusMessage(ncmpEventResponseCode.getStatusMessage());
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java
index 7f8cbf676e..78b000dae6 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/ResponseTimeoutTask.java
@@ -24,7 +24,7 @@ import com.hazelcast.map.IMap;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent;
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent;
@Slf4j
@RequiredArgsConstructor
@@ -32,7 +32,7 @@ public class ResponseTimeoutTask implements Runnable {
private final IMap<String, Set<String>> forwardedSubscriptionEventCache;
private final CmSubscriptionNcmpOutEventPublisher cmSubscriptionNcmpOutEventPublisher;
- private final CmSubscriptionDmiOutEvent cmSubscriptionDmiOutEvent;
+ private final CmSubscriptionEvent cmSubscriptionEvent;
@Override
public void run() {
@@ -40,11 +40,11 @@ public class ResponseTimeoutTask implements Runnable {
}
private void generateTimeoutResponse() {
- final String subscriptionClientId = cmSubscriptionDmiOutEvent.getData().getClientId();
- final String subscriptionName = cmSubscriptionDmiOutEvent.getData().getSubscriptionName();
+ final String subscriptionClientId = cmSubscriptionEvent.getClientId();
+ final String subscriptionName = cmSubscriptionEvent.getSubscriptionName();
final String subscriptionEventId = subscriptionClientId + subscriptionName;
if (forwardedSubscriptionEventCache.containsKey(subscriptionEventId)) {
- cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionDmiOutEvent,
+ cmSubscriptionNcmpOutEventPublisher.sendResponse(cmSubscriptionEvent,
"subscriptionCreatedStatus");
forwardedSubscriptionEventCache.remove(subscriptionEventId);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionEvent.java
new file mode 100644
index 0000000000..2a60b2ab16
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionEvent.java
@@ -0,0 +1,50 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.models;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Getter
+@Setter
+public class CmSubscriptionEvent {
+
+ @JsonProperty("clientId")
+ @NotNull
+ private String clientId;
+
+ @JsonProperty("subscriptionName")
+ @NotNull
+ private String subscriptionName;
+
+ @JsonProperty("cmSubscriptionStatus")
+ @Valid
+ @NotNull
+ private List<CmSubscriptionStatus> cmSubscriptionStatus = new ArrayList<>();
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java
new file mode 100644
index 0000000000..bba560785d
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmSubscriptionStatus.java
@@ -0,0 +1,45 @@
+/*
+ * ============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.models;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import javax.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Getter
+@Setter
+public class CmSubscriptionStatus {
+
+ @JsonProperty("id")
+ @NotNull
+ private String id;
+
+ @JsonProperty("status")
+ @NotNull
+ private SubscriptionStatus status;
+
+ @JsonProperty("details")
+ private String details;
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy
index a8a21b2edd..175ead8062 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy
@@ -46,24 +46,22 @@ class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec {
IMap<String, Set<String>> mockForwardedSubscriptionEventCache = Mock(IMap<String, Set<String>>)
def mockSubscriptionPersistence = Mock(SubscriptionPersistenceImpl)
def mockSubscriptionEventResponseMapper = Mock(CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapper)
- def mockSubscriptionEventResponseOutcome = Mock(CmSubscriptionNcmpOutEventPublisher)
+ def mockCmSubscriptionNcmpOutEventPublisher = Mock(CmSubscriptionNcmpOutEventPublisher)
def objectUnderTest = new CmSubscriptionDmiOutEventConsumer(mockForwardedSubscriptionEventCache,
- mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockSubscriptionEventResponseOutcome)
+ mockSubscriptionPersistence, mockSubscriptionEventResponseMapper, mockCmSubscriptionNcmpOutEventPublisher)
- def 'Consume Subscription Event Response where all DMIs have responded'() {
- given: 'a consumer record including cloud event having subscription response'
- def consumerRecordWithCloudEventAndSubscriptionResponse = getConsumerRecord()
- and: 'a subscription response event'
- def subscriptionResponseEvent = getSubscriptionResponseEvent()
- and: 'a subscription event response and notifications are enabled'
+ def 'Consume dmi out event where all DMIs have responded'() {
+ given: 'a consumer record including cloud event having dmi out event'
+ def dmiOutConsumerRecord = getDmiOutConsumerRecord()
+ and: 'notifications are enabled'
objectUnderTest.notificationFeatureEnabled = notificationEnabled
and: 'subscription model loader is enabled'
objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled
and: 'subscription persistence service returns data node includes no pending cm handle'
mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [getDataNode()]
when: 'the valid event is consumed'
- objectUnderTest.consumeSubscriptionEventResponse(consumerRecordWithCloudEventAndSubscriptionResponse)
+ objectUnderTest.consumeDmiOutEvent(dmiOutConsumerRecord)
then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event'
1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true
1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['some-dmi-name'] as Set)
@@ -76,7 +74,7 @@ class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec {
and: 'the subscription event is removed from the map'
numberOfTimeToRemove * mockForwardedSubscriptionEventCache.remove('SCO-9989752cm-subscription-001')
and: 'a response outcome has been created'
- numberOfTimeToResponse * mockSubscriptionEventResponseOutcome.sendResponse(subscriptionResponseEvent, 'subscriptionCreated')
+ numberOfTimeToResponse * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(_, 'subscriptionCreated')
where: 'the following values are used'
scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist || numberOfTimeToRemove || numberOfTimeToResponse
'Both model loader and notification are enabled' | true | true || 1 || 1 || 1
@@ -85,13 +83,13 @@ class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec {
'Model loader disabled and notification enabled' | false | true || 0 || 1 || 1
}
- def 'Consume Subscription Event Response where another DMI has not yet responded'() {
+ def 'Consume dmi out event where another DMI has not yet responded'() {
given: 'a subscription event response and notifications are enabled'
objectUnderTest.notificationFeatureEnabled = notificationEnabled
and: 'subscription model loader is enabled'
objectUnderTest.subscriptionModelLoaderEnabled = modelLoaderEnabled
when: 'the valid event is consumed'
- objectUnderTest.consumeSubscriptionEventResponse(getConsumerRecord())
+ objectUnderTest.consumeDmiOutEvent(getDmiOutConsumerRecord())
then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event'
1 * mockForwardedSubscriptionEventCache.containsKey('SCO-9989752cm-subscription-001') >> true
1 * mockForwardedSubscriptionEventCache.get('SCO-9989752cm-subscription-001') >> (['responded-dmi', 'non-responded-dmi'] as Set)
@@ -105,7 +103,7 @@ class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec {
and: 'the subscription event is not removed from the map'
0 * mockForwardedSubscriptionEventCache.remove(_)
and: 'a response outcome has not been created'
- 0 * mockSubscriptionEventResponseOutcome.sendResponse(*_)
+ 0 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(*_)
where: 'the following values are used'
scenario | modelLoaderEnabled | notificationEnabled || numberOfTimeToPersist
'Both model loader and notification are enabled' | true | true || 1
@@ -114,21 +112,21 @@ class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec {
'Model loader disabled and notification enabled' | false | true || 0
}
- def getSubscriptionResponseEvent() {
- def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
- return jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class)
+ def getDmiOutEvent() {
+ def cmSubscriptionDmiOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
+ return jsonObjectMapper.convertJsonString(cmSubscriptionDmiOutEventJsonData, CmSubscriptionDmiOutEvent.class)
}
- def getCloudEventHavingSubscriptionResponseEvent() {
+ def getCloudEvent() {
return CloudEventBuilder.v1()
- .withData(objectMapper.writeValueAsBytes(getSubscriptionResponseEvent()))
+ .withData(objectMapper.writeValueAsBytes(getDmiOutEvent()))
.withId('some-id')
.withType('subscriptionCreated')
.withSource(URI.create('NCMP')).build()
}
- def getConsumerRecord() {
- return new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', getCloudEventHavingSubscriptionResponseEvent())
+ def getDmiOutConsumerRecord() {
+ return new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', getCloudEvent())
}
def getDataNode() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy
index 036bedb8af..b13a2ceba1 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec.groovy
@@ -39,8 +39,8 @@ class CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec extends Sp
@Autowired
JsonObjectMapper jsonObjectMapper
- def 'Map subscription response event to yang model subscription event'() {
- given: 'a Subscription Response Event'
+ def 'Map dmi out event to yang model subscription event'() {
+ given: 'a dmi out event'
def jsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
def testEventToMap = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionDmiOutEvent.class)
when: 'the event is mapped to a yang model subscription'
@@ -50,11 +50,11 @@ class CmSubscriptionDmiOutEventToYangModelSubscriptionEventMapperSpec extends Sp
and: 'subscription name'
assert result.subscriptionName == "cm-subscription-001"
and: 'predicate targets cm handle size as expected'
- assert result.predicates.targetCmHandles.size() == 4
+ assert result.predicates.targetCmHandles.size() == 2
and: 'predicate targets cm handle ids as expected'
- assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2", "CMHandle3", "CMHandle4"]
+ assert result.predicates.targetCmHandles.cmHandleId == ["CMHandle1", "CMHandle2"]
and: 'the status for these targets is set to expected values'
- assert result.predicates.targetCmHandles.status == [SubscriptionStatus.REJECTED, SubscriptionStatus.REJECTED, SubscriptionStatus.PENDING, SubscriptionStatus.PENDING]
+ assert result.predicates.targetCmHandles.status == [SubscriptionStatus.REJECTED, SubscriptionStatus.REJECTED]
}
} \ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy
index df5167da94..07b0925dcf 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec.groovy
@@ -22,8 +22,8 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription
import com.fasterxml.jackson.databind.ObjectMapper
import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.SubscriptionStatus
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent
+import org.onap.cps.ncmp.api.models.CmSubscriptionStatus
import org.onap.cps.ncmp.utils.TestUtils
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.utils.JsonObjectMapper
@@ -33,24 +33,26 @@ import spock.lang.Specification
@SpringBootTest(classes = [JsonObjectMapper, ObjectMapper])
-class CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec extends Specification {
+class CmSubscriptionEventToCmSubscriptionNcmpOutEventMapperSpec extends Specification {
- CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper)
+ CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper objectUnderTest = Mappers.getMapper(CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper)
@Autowired
JsonObjectMapper jsonObjectMapper
- def 'Map subscription event response to subscription event outcome'() {
- given: 'a Subscription Response Event'
- def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
- def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class)
- when: 'the subscription response event is mapped to a subscription event outcome'
- def result = objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent)
- then: 'the resulting subscription event outcome contains expected pending targets per details grouping'
+ def 'Map cm subscription event to ncmp out event'() {
+ given: 'a cm subscription event'
+ def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json')
+ def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class)
+ when: 'cm subscription event is mapped to ncmp out event'
+ def result = objectUnderTest.toCmSubscriptionNcmpOutEvent(cmSubscriptionEvent)
+ then: 'the resulting ncmp out event contains expected pending targets per details grouping'
def pendingCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getPending()
- assert pendingCmHandleTargetsPerDetails.get(0).getDetails() == 'No reply from DMI yet'
- assert pendingCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle3', 'CMHandle4']
- and: 'the resulting subscription event outcome contains expected rejected targets per details grouping'
+ assert pendingCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error happened'
+ assert pendingCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle4','CMHandle5']
+ assert pendingCmHandleTargetsPerDetails.get(1).getDetails() == 'Some error causes pending'
+ assert pendingCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle3']
+ and: 'the resulting ncmp out event contains expected rejected targets per details grouping'
def rejectedCmHandleTargetsPerDetails = result.getData().getAdditionalInfo().getRejected()
assert rejectedCmHandleTargetsPerDetails.get(0).getDetails() == 'Some other error message from the DMI'
assert rejectedCmHandleTargetsPerDetails.get(0).getTargets() == ['CMHandle2']
@@ -58,28 +60,28 @@ class CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapperSpec extends Sp
assert rejectedCmHandleTargetsPerDetails.get(1).getTargets() == ['CMHandle1']
}
- def 'Map subscription event response with null of subscription status list to subscription event outcome causes an exception'() {
- given: 'a Subscription Response Event'
- def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
- def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class)
- and: 'set subscription status list to null'
- subscriptionResponseEvent.getData().setSubscriptionStatus(subscriptionStatusList)
- when: 'the subscription response event is mapped to a subscription event outcome'
- objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent)
+ def 'Map cm subscription event to ncmp out event with the given scenarios causes an exception'() {
+ given: 'a cm subscription event'
+ def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json')
+ def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class)
+ and: 'set cm subscription status with given scenarios'
+ cmSubscriptionEvent.setCmSubscriptionStatus(subscriptionStatusList)
+ when: 'cm subscription event is mapped to ncmp out event'
+ objectUnderTest.toCmSubscriptionNcmpOutEvent(cmSubscriptionEvent)
then: 'a DataValidationException is thrown with an expected exception details'
def exception = thrown(DataValidationException)
- exception.details == 'SubscriptionStatus list cannot be null or empty'
+ exception.details == 'CmSubscriptionStatus list cannot be null or empty'
where: 'the following values are used'
scenario || subscriptionStatusList
- 'A null subscription status list' || null
- 'An empty subscription status list' || new ArrayList<SubscriptionStatus>()
+ 'A null subscription status list' || null
+ 'An empty subscription status list' || new ArrayList<CmSubscriptionStatus>()
}
- def 'Map subscription event response with subscription status list to subscription event outcome without any exception'() {
- given: 'a Subscription Response Event'
- def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
- def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class)
- when: 'the subscription response event is mapped to a subscription event outcome'
+ def 'Map cm subscription event to ncmp out event without any exception'() {
+ given: 'a cm subscription Event'
+ def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json')
+ def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionEvent.class)
+ when: 'cm subscription event is mapped to ncmp out event'
objectUnderTest.toCmSubscriptionNcmpOutEvent(subscriptionResponseEvent)
then: 'no exception thrown'
noExceptionThrown()
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy
index a13fe53e82..fd1a83ee08 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy
@@ -32,6 +32,7 @@ import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent.TargetCmHandle
import org.onap.cps.ncmp.api.inventory.InventoryPersistence
import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent
import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent
import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent
import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.Data
@@ -74,24 +75,25 @@ class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec {
ObjectMapper objectMapper
def 'Forward valid CM create subscription and simulate timeout'() {
- given: 'an event'
- def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json')
- def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class)
+ given: 'a ncmp in event'
+ def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json')
+ def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class)
and: 'the InventoryPersistence returns private properties for the supplied CM Handles'
1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> [
- createYangModelCmHandleWithDmiProperty(1, 1, "shape", "circle"),
- createYangModelCmHandleWithDmiProperty(2, 1, "shape", "square")
+ createYangModelCmHandleWithDmiProperty(1, 1,"shape","circle"),
+ createYangModelCmHandleWithDmiProperty(2, 1,"shape","square"),
+ createYangModelCmHandleWithDmiProperty(3, 2,"shape","triangle")
]
and: 'the thread creation delay is reduced to 2 seconds for testing'
objectUnderTest.dmiResponseTimeoutInMs = 2000
and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds'
def block = new BlockingVariable<Object>(5)
when: 'the valid event is forwarded'
- objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreated')
+ objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'subscriptionCreated')
then: 'An asynchronous call is made to the blocking variable'
block.get()
then: 'the event is added to the forwarded subscription event cache'
- 1 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1"] as Set, 600, TimeUnit.SECONDS)
+ 1 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1","DMIName2"] as Set, 600, TimeUnit.SECONDS)
and: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future'
1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1",
cloudEvent -> {
@@ -101,6 +103,13 @@ class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec {
targets == [cmHandle2, cmHandle1]
}
)
+ 1 * mockSubscriptionEventPublisher.publishCloudEvent("ncmp-dmi-cm-avc-subscription-DMIName2", "SCO-9989752-cm-subscription-001-DMIName2",
+ cloudEvent -> {
+ def targets = toTargetEvent(cloudEvent, CmSubscriptionDmiInEvent.class).getData().getPredicates().getTargets()
+ def cmHandle3 = createCmHandle('CMHandle3', ['shape':'triangle'] as Map)
+ targets == [cmHandle3]
+ }
+ )
and: 'a separate thread has been created where the map is polled'
1 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true
1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(*_)
@@ -109,13 +118,13 @@ class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec {
}
def 'Forward CM create subscription where target CM Handles are #scenario'() {
- given: 'an event'
- def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json')
- def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class)
+ given: 'a ncmp in event'
+ def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json')
+ def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class)
and: 'the target CMHandles are set to #scenario'
- testEventSent.getData().getPredicates().setTargets(invalidTargets)
+ ncmpInEventJson.getData().getPredicates().setTargets(invalidTargets)
when: 'the event is forwarded'
- objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'some-event-type')
+ objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'some-event-type')
then: 'an operation not supported exception is thrown'
thrown(UnsupportedOperationException)
where:
@@ -126,28 +135,24 @@ class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec {
}
def 'Forward valid CM create subscription where targets are not associated to any existing CMHandles'() {
- given: 'an event'
- def jsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json')
- def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmSubscriptionNcmpInEvent.class)
- and: 'a subscription event response'
- def emptySubscriptionEventResponse = new CmSubscriptionDmiOutEvent().withData(new Data());
- emptySubscriptionEventResponse.getData().setSubscriptionName('cm-subscription-001');
- emptySubscriptionEventResponse.getData().setClientId('SCO-9989752');
- and: 'the cm handles will be rejected'
+ given: 'a ncmp in event'
+ def ncmpInEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpInEvent.json')
+ def ncmpInEventJson = jsonObjectMapper.convertJsonString(ncmpInEventJsonData, CmSubscriptionNcmpInEvent.class)
+ and: 'the InventoryPersistence returns no private properties for the supplied CM Handles'
+ 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> []
+ and: 'some rejected cm handles'
def rejectedCmHandles = [new TargetCmHandle('CMHandle1', SubscriptionStatus.REJECTED, 'Cm handle does not exist'),
new TargetCmHandle('CMHandle2', SubscriptionStatus.REJECTED, 'Cm handle does not exist'),
new TargetCmHandle('CMHandle3', SubscriptionStatus.REJECTED, 'Cm handle does not exist')]
and: 'a yang model subscription event will be saved into the db with rejected cm handles'
- def yangModelSubscriptionEvent = cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(testEventSent)
+ def yangModelSubscriptionEvent = cmSubscriptionNcmpInEventMapper.toYangModelSubscriptionEvent(ncmpInEventJson)
yangModelSubscriptionEvent.getPredicates().setTargetCmHandles(rejectedCmHandles)
- and: 'the InventoryPersistence returns no private properties for the supplied CM Handles'
- 1 * mockInventoryPersistence.getYangModelCmHandles(["CMHandle1", "CMHandle2", "CMHandle3"]) >> []
and: 'the thread creation delay is reduced to 2 seconds for testing'
objectUnderTest.dmiResponseTimeoutInMs = 2000
and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds'
def block = new BlockingVariable<Object>(5)
when: 'the valid event is forwarded'
- objectUnderTest.forwardCreateSubscriptionEvent(testEventSent, 'subscriptionCreatedStatus')
+ objectUnderTest.forwardCreateSubscriptionEvent(ncmpInEventJson, 'subscriptionCreatedStatus')
then: 'the event is not added to the forwarded subscription event cache'
0 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1", "DMIName2"] as Set)
and: 'the event is not being forwarded with the CMHandle private properties and does not provides a valid listenable future'
@@ -170,11 +175,11 @@ class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec {
0 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true
0 * mockForwardedSubscriptionEventCache.get(_)
and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable'
- 0 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> { block.set(_) }
- and: 'the persistence service save target cm handles of the yang model subscription event as rejected '
+ 0 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)}
+ and: 'the persistence service save target cm handles of the yang model subscription event as rejected'
1 * mockSubscriptionPersistence.saveSubscriptionEvent(yangModelSubscriptionEvent)
and: 'subscription outcome has been sent'
- 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(emptySubscriptionEventResponse, 'subscriptionCreatedStatus')
+ 1 * mockCmSubscriptionNcmpOutEventPublisher.sendResponse(_, 'subscriptionCreatedStatus')
}
static def createYangModelCmHandleWithDmiProperty(id, dmiId, propertyName, propertyValue) {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy
index 07e2e3f6a5..cc14195191 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy
@@ -29,7 +29,7 @@ import org.onap.cps.ncmp.api.impl.events.EventsPublisher
import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence
import org.onap.cps.ncmp.api.impl.utils.DataNodeBaseSpec
import org.onap.cps.ncmp.api.impl.utils.SubscriptionOutcomeCloudMapper
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent
+import org.onap.cps.ncmp.api.models.CmSubscriptionEvent
import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent
import org.onap.cps.ncmp.utils.TestUtils
import org.onap.cps.utils.JsonObjectMapper
@@ -37,7 +37,7 @@ import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
-@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper, CmSubscriptionNcmpOutEventPublisher])
+@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper, CmSubscriptionNcmpOutEventPublisher])
class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec {
@Autowired
@@ -48,7 +48,7 @@ class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec {
@SpringBean
EventsPublisher<CloudEvent> mockCmSubscriptionNcmpOutEventPublisher = Mock(EventsPublisher<CloudEvent>)
@SpringBean
- CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper cmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper = Mappers.getMapper(CmSubscriptionDmiOutEventToCmSubscriptionNcmpOutEventMapper)
+ CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper = Mappers.getMapper(CmSubscriptionEventToCmSubscriptionNcmpOutEventMapper)
@SpringBean
SubscriptionOutcomeCloudMapper subscriptionOutcomeCloudMapper = new SubscriptionOutcomeCloudMapper(new ObjectMapper())
@@ -59,17 +59,17 @@ class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec {
ObjectMapper objectMapper
def 'Send response to the client apps successfully'() {
- given: 'a subscription response event'
- def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
- def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class)
- and: 'a subscription outcome event'
- def subscriptionOutcomeJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent2.json')
- def subscriptionOutcomeEvent = jsonObjectMapper.convertJsonString(subscriptionOutcomeJsonData, CmSubscriptionNcmpOutEvent.class)
+ given: 'a cm subscription event'
+ def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json')
+ def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class)
+ and: 'a ncmp out event'
+ def ncmpOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent2.json')
+ def ncmpOutEvent = jsonObjectMapper.convertJsonString(ncmpOutEventJsonData, CmSubscriptionNcmpOutEvent.class)
and: 'a random id for the cloud event'
SubscriptionOutcomeCloudMapper.randomId = 'some-id'
and: 'a cloud event containing the outcome event'
def testCloudEventSent = CloudEventBuilder.v1()
- .withData(objectMapper.writeValueAsBytes(subscriptionOutcomeEvent))
+ .withData(objectMapper.writeValueAsBytes(ncmpOutEvent))
.withId('some-id')
.withType('subscriptionCreatedStatus')
.withDataSchema(URI.create('urn:cps:' + 'org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_client.CmSubscriptionNcmpOutEvent' + ':1.0.0'))
@@ -78,25 +78,25 @@ class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec {
and: 'the persistence service return a data node that includes pending cm handles that makes it partial success'
mockSubscriptionPersistence.getCmHandlesForSubscriptionEvent(*_) >> [dataNode4]
when: 'the response is being sent'
- objectUnderTest.sendResponse(subscriptionResponseEvent, 'subscriptionCreatedStatus')
+ objectUnderTest.sendResponse(cmSubscriptionEvent, 'subscriptionCreatedStatus')
then: 'the publisher publish the cloud event with itself and expected parameters'
1 * mockCmSubscriptionNcmpOutEventPublisher.publishCloudEvent('subscription-response', 'SCO-9989752cm-subscription-001', testCloudEventSent)
}
- def 'Create subscription outcome message as expected'() {
- given: 'a subscription response event'
- def subscriptionResponseJsonData = TestUtils.getResourceFileContent('cmSubscriptionDmiOutEvent.json')
- def subscriptionResponseEvent = jsonObjectMapper.convertJsonString(subscriptionResponseJsonData, CmSubscriptionDmiOutEvent.class)
- and: 'a subscription outcome event'
- def subscriptionOutcomeJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent.json')
- def subscriptionOutcomeEvent = jsonObjectMapper.convertJsonString(subscriptionOutcomeJsonData, CmSubscriptionNcmpOutEvent.class)
+ def 'Create ncmp out message as expected'() {
+ given: 'a cm subscription event'
+ def cmSubscriptionEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionEvent.json')
+ def cmSubscriptionEvent = jsonObjectMapper.convertJsonString(cmSubscriptionEventJsonData, CmSubscriptionEvent.class)
+ and: 'a ncmp out event'
+ def ncmpOutEventJsonData = TestUtils.getResourceFileContent('cmSubscriptionNcmpOutEvent.json')
+ def ncmpOutEvent = jsonObjectMapper.convertJsonString(ncmpOutEventJsonData, CmSubscriptionNcmpOutEvent.class)
and: 'a status code and status message a per #scenarios'
- subscriptionOutcomeEvent.getData().setStatusCode(statusCode)
- subscriptionOutcomeEvent.getData().setStatusMessage(statusMessage)
- when: 'a subscription event outcome message is being formed'
- def result = objectUnderTest.fromDmiOutEvent(subscriptionResponseEvent, ncmpEventResponseCode)
- then: 'the result will be equal to event outcome'
- result == subscriptionOutcomeEvent
+ ncmpOutEvent.getData().setStatusCode(statusCode)
+ ncmpOutEvent.getData().setStatusMessage(statusMessage)
+ when: 'a cm subscription event is being formed'
+ def expectedResult = objectUnderTest.fromCmSubscriptionEvent(cmSubscriptionEvent, ncmpEventResponseCode)
+ then: 'the result will be equal to ncmp out event'
+ expectedResult == ncmpOutEvent
where: 'the following values are used'
scenario | ncmpEventResponseCode || statusMessage || statusCode
'is full outcome' | NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION || 'successfully applied subscription' || 1
diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json b/cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json
index dfe8f50466..ae14b5ca21 100644
--- a/cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json
+++ b/cps-ncmp-service/src/test/resources/cmSubscriptionDmiOutEvent.json
@@ -13,16 +13,6 @@
"id": "CMHandle2",
"status": "REJECTED",
"details": "Some other error message from the DMI"
- },
- {
- "id": "CMHandle3",
- "status": "PENDING",
- "details": "No reply from DMI yet"
- },
- {
- "id": "CMHandle4",
- "status": "PENDING",
- "details": "No reply from DMI yet"
}
]
}
diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionEvent.json b/cps-ncmp-service/src/test/resources/cmSubscriptionEvent.json
new file mode 100644
index 0000000000..c38cb79211
--- /dev/null
+++ b/cps-ncmp-service/src/test/resources/cmSubscriptionEvent.json
@@ -0,0 +1,31 @@
+{
+ "clientId": "SCO-9989752",
+ "subscriptionName": "cm-subscription-001",
+ "cmSubscriptionStatus": [
+ {
+ "id": "CMHandle1",
+ "status": "REJECTED",
+ "details": "Some error message from the DMI"
+ },
+ {
+ "id": "CMHandle2",
+ "status": "REJECTED",
+ "details": "Some other error message from the DMI"
+ },
+ {
+ "id": "CMHandle3",
+ "status": "PENDING",
+ "details": "Some error causes pending"
+ },
+ {
+ "id": "CMHandle4",
+ "status": "PENDING",
+ "details": "Some other error happened"
+ },
+ {
+ "id": "CMHandle5",
+ "status": "PENDING",
+ "details": "Some other error happened"
+ }
+ ]
+} \ No newline at end of file
diff --git a/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json
index 14e8cbb4c4..856f238c6e 100644
--- a/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json
+++ b/cps-ncmp-service/src/test/resources/cmSubscriptionNcmpOutEvent.json
@@ -15,8 +15,12 @@
],
"pending": [
{
- "details": "No reply from DMI yet",
- "targets": ["CMHandle3", "CMHandle4"]
+ "details": "Some other error happened",
+ "targets": ["CMHandle4", "CMHandle5"]
+ },
+ {
+ "details": "Some error causes pending",
+ "targets": ["CMHandle3"]
}
]
}