Merge "Adding NCMP Stubs documentation"
authorToine Siebelink <toine.siebelink@est.tech>
Mon, 16 Oct 2023 16:12:25 +0000 (16:12 +0000)
committerGerrit Code Review <gerrit@onap.org>
Mon, 16 Oct 2023 16:12:25 +0000 (16:12 +0000)
22 files changed:
cps-ncmp-events/src/main/resources/schemas/trustlevel/device-trust-level-event-schema-1.0.0.json [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelFilter.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DMiPluginWatchDog.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditions.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapperSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelFilterSpec.groovy [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceTrustLevel.java with 55% similarity]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DMiPluginWatchDogSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditionsSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImplSpec.groovy

diff --git a/cps-ncmp-events/src/main/resources/schemas/trustlevel/device-trust-level-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/trustlevel/device-trust-level-event-schema-1.0.0.json
new file mode 100644 (file)
index 0000000..e1796fb
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "$id": "urn:cps:org.onap.cps.ncmp.events:device-trust-level-event-schema:1.0.0",
+  "$ref": "#/definitions/DeviceTrustLevel",
+  "definitions": {
+    "DeviceTrustLevel" : {
+      "description": "The payload for device trust level event.",
+      "type": "object",
+      "javaType": "org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel",
+      "properties": {
+        "data": {
+          "type": "object",
+          "properties": {
+            "trustLevel": {
+              "type": "string"
+            }
+          },
+          "required": [
+            "trustLevel"
+          ],
+          "additionalProperties": false
+        }
+      },
+      "additionalProperties": false,
+      "required": [
+        "data"
+      ]
+    }
+  }
+}
\ No newline at end of file
index 7475cdd..1f6c948 100644 (file)
@@ -24,6 +24,7 @@ import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DM
 import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.HAS_ALL_MODULES;
 import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.HAS_ALL_PROPERTIES;
 import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.WITH_CPS_PATH;
+import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.WITH_TRUST_LEVEL;
 import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateCpsPathConditionProperties;
 import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateModuleNameConditionProperties;
 import static org.onap.cps.ncmp.api.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle;
@@ -70,7 +71,8 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
         return executeQueries(cmHandleQueryServiceParameters,
             this::executeCpsPathQuery,
             this::queryCmHandlesByPublicProperties,
-            this::executeModuleNameQuery);
+            this::executeModuleNameQuery,
+                this::queryCmHandlesByTrustLevel);
     }
 
     @Override
@@ -117,9 +119,10 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
                         InventoryQueryConditions.HAS_ALL_ADDITIONAL_PROPERTIES.getName());
 
-        return privatePropertyQueryPairs.isEmpty()
-                ? NO_QUERY_TO_EXECUTE
-                : cmHandleQueries.queryCmHandleAdditionalProperties(privatePropertyQueryPairs);
+        if (privatePropertyQueryPairs.isEmpty()) {
+            return NO_QUERY_TO_EXECUTE;
+        }
+        return cmHandleQueries.queryCmHandleAdditionalProperties(privatePropertyQueryPairs);
     }
 
     private Collection<String> queryCmHandlesByPublicProperties(
@@ -129,9 +132,23 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
                         HAS_ALL_PROPERTIES.getConditionName());
 
-        return publicPropertyQueryPairs.isEmpty()
-                ? NO_QUERY_TO_EXECUTE
-                : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
+        if (publicPropertyQueryPairs.isEmpty()) {
+            return NO_QUERY_TO_EXECUTE;
+        }
+        return cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
+    }
+
+    private Collection<String> queryCmHandlesByTrustLevel(final CmHandleQueryServiceParameters
+                                                                  cmHandleQueryServiceParameters) {
+
+        final Map<String, String> trustLevelPropertyQueryPairs =
+                getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
+                        WITH_TRUST_LEVEL.getConditionName());
+
+        if (trustLevelPropertyQueryPairs.isEmpty()) {
+            return NO_QUERY_TO_EXECUTE;
+        }
+        return cmHandleQueries.queryCmHandlesByTrustLevel(trustLevelPropertyQueryPairs);
     }
 
     private Collection<String> executeModuleNameQuery(
index 692a9f2..a37b271 100755 (executable)
@@ -99,7 +99,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler;
     private final CpsDataService cpsDataService;
     private final IMap<String, Object> moduleSyncStartedOnCmHandles;
-    private final IMap<String, TrustLevel> trustLevelPerDmiPlugin;
+    private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
 
     @Override
     public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
index 6a8310c..e8ce050 100644 (file)
@@ -75,10 +75,8 @@ public class DmiRestClient {
             final HttpEntity<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders()));
             final JsonNode dmiPluginHealthStatus = restTemplate.getForObject(dmiPluginBaseUrl + "/manage/health",
                     JsonNode.class, httpHeaders);
-            if (dmiPluginHealthStatus != null) {
-                if (dmiPluginHealthStatus.get("status").asText().equals("UP")) {
-                    return DmiPluginStatus.UP;
-                }
+            if (dmiPluginHealthStatus != null && dmiPluginHealthStatus.get("status").asText().equals("UP")) {
+                return DmiPluginStatus.UP;
             }
         } catch (final Exception exception) {
             log.warn("Could not send request for health check since {}", exception.getMessage());
index ebe9905..171db52 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.config.embeddedcache;
 
-import com.hazelcast.collection.ISet;
 import com.hazelcast.config.MapConfig;
-import com.hazelcast.config.SetConfig;
-import com.hazelcast.map.IMap;
+import java.util.Map;
 import org.onap.cps.cache.HazelcastCacheConfig;
 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel;
 import org.springframework.context.annotation.Bean;
@@ -32,21 +30,21 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 public class TrustLevelCacheConfig extends HazelcastCacheConfig {
 
-    private static final SetConfig untrustworthyCmHandlesSetConfig =
-            createSetConfig("untrustworthyCmHandlesSetConfig");
+    private static final MapConfig trustLevelPerCmHandleCacheConfig =
+            createMapConfig("trustLevelPerCmHandleCacheConfig");
 
     private static final MapConfig trustLevelPerDmiPluginCacheConfig =
             createMapConfig("trustLevelPerDmiPluginCacheConfig");
 
     /**
-     * Distributed collection of untrustworthy cm handles.
+     * Distributed instance of trust level cache containing the trust level per cm handle.
      *
-     * @return instance of distributed set of untrustworthy cm handles.
+     * @return configured map of cm handle name as keys to trust-level for values.
      */
     @Bean
-    public ISet<String> untrustworthyCmHandlesSet() {
-        return createHazelcastInstance("untrustworthyCmHandlesSet",
-                untrustworthyCmHandlesSetConfig).getSet("untrustworthyCmHandlesSet");
+    public Map<String, TrustLevel> trustLevelPerCmHandle() {
+        return createHazelcastInstance("hazelcastInstanceTrustLevelPerCmHandleMap",
+                trustLevelPerCmHandleCacheConfig).getMap("trustLevelPerCmHandle");
     }
 
     /**
@@ -55,7 +53,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig {
      * @return configured map of dmi-plugin name as keys to trust-level for values.
      */
     @Bean
-    public IMap<String, TrustLevel> trustLevelPerDmiPlugin() {
+    public Map<String, TrustLevel> trustLevelPerDmiPlugin() {
         return createHazelcastInstance("hazelcastInstanceTrustLevelPerDmiPluginMap",
                 trustLevelPerDmiPluginCacheConfig).getMap("trustLevelPerDmiPlugin");
     }
index 98ba953..4120970 100644 (file)
@@ -25,7 +25,6 @@ import io.cloudevents.CloudEvent;
 import io.cloudevents.core.CloudEventUtils;
 import io.cloudevents.core.data.PojoCloudEventData;
 import io.cloudevents.jackson.PojoCloudEventDataMapper;
-import io.cloudevents.rw.CloudEventRWException;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -51,9 +50,9 @@ public class CloudEventMapper {
             mappedCloudEvent =
                     CloudEventUtils.mapData(cloudEvent, PojoCloudEventDataMapper.from(objectMapper, targetEventClass));
 
-        } catch (final CloudEventRWException cloudEventRwException) {
+        } catch (final RuntimeException runtimeException) {
             log.error("Unable to map cloud event to target event class type : {} with cause : {}", targetEventClass,
-                    cloudEventRwException.getMessage());
+                    runtimeException.getMessage());
         }
 
         return mappedCloudEvent == null ? null : mappedCloudEvent.getValue();
index a5892af..81467db 100644 (file)
@@ -44,6 +44,14 @@ public interface CmHandleQueries {
      */
     Collection<String> queryCmHandlePublicProperties(Map<String, String> publicPropertyQueryPairs);
 
+    /**
+     * Query CmHandles based on Trust Level.
+     *
+     * @param trustLevelPropertyQueryPairs trust level properties for query
+     * @return CmHandles which have desired trust level
+     */
+    Collection<String> queryCmHandlesByTrustLevel(Map<String, String> trustLevelPropertyQueryPairs);
+
     /**
      * Method which returns cm handles by the cm handles state.
      *
index c4e3fd0..e5cf8ed 100644 (file)
@@ -35,6 +35,8 @@ import java.util.Map;
 import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import org.onap.cps.ncmp.api.impl.inventory.enums.PropertyType;
+import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel;
+import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelFilter;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.DataNode;
@@ -45,9 +47,9 @@ import org.springframework.stereotype.Component;
 public class CmHandleQueriesImpl implements CmHandleQueries {
 
     private static final String DESCENDANT_PATH = "//";
-
-    private final CpsDataPersistenceService cpsDataPersistenceService;
     private static final String ANCESTOR_CM_HANDLES = "/ancestor::cm-handles";
+    private final CpsDataPersistenceService cpsDataPersistenceService;
+    private final Map<String, TrustLevel> trustLevelPerCmHandle;
 
     @Override
     public Collection<String> queryCmHandleAdditionalProperties(final Map<String, String> privatePropertyQueryPairs) {
@@ -59,6 +61,15 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
         return queryCmHandleAnyProperties(publicPropertyQueryPairs, PropertyType.PUBLIC);
     }
 
+    @Override
+    public Collection<String> queryCmHandlesByTrustLevel(final Map<String, String> trustLevelPropertyQueryPairs) {
+        final String trustLevelProperty = trustLevelPropertyQueryPairs.values().iterator().next();
+        final TrustLevel targetTrustLevel = TrustLevel.valueOf(trustLevelProperty);
+
+        final TrustLevelFilter trustLevelFilter = new TrustLevelFilter(targetTrustLevel, trustLevelPerCmHandle);
+        return trustLevelFilter.getAllCmHandleIdsByTargetTrustLevel();
+    }
+
     @Override
     public List<DataNode> queryCmHandlesByState(final CmHandleState cmHandleState) {
         return queryCmHandleAncestorsByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]",
index 458c1b8..b6d74d9 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.trustlevel;
 
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent;
-
-import com.hazelcast.collection.ISet;
 import io.cloudevents.CloudEvent;
 import io.cloudevents.kafka.impl.KafkaHeaders;
+import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper;
+import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel;
 import org.springframework.kafka.annotation.KafkaListener;
 import org.springframework.stereotype.Component;
 
@@ -36,7 +36,8 @@ import org.springframework.stereotype.Component;
 @RequiredArgsConstructor
 public class DeviceHeartbeatConsumer {
 
-    private final ISet<String> untrustworthyCmHandlesSet;
+    private static final String CLOUD_EVENT_ID_HEADER_NAME = "ce_id";
+    private final Map<String, TrustLevel> trustLevelPerCmHandle;
 
     /**
      * Listening the device heartbeats.
@@ -47,23 +48,16 @@ public class DeviceHeartbeatConsumer {
             containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory")
     public void heartbeatListener(final ConsumerRecord<String, CloudEvent> deviceHeartbeatConsumerRecord) {
 
-        final String cmHandleId = KafkaHeaders.getParsedKafkaHeader(deviceHeartbeatConsumerRecord.headers(), "ce_id");
+        final String cmHandleId = KafkaHeaders.getParsedKafkaHeader(deviceHeartbeatConsumerRecord.headers(),
+                CLOUD_EVENT_ID_HEADER_NAME);
 
         final DeviceTrustLevel deviceTrustLevel =
-                toTargetEvent(deviceHeartbeatConsumerRecord.value(), DeviceTrustLevel.class);
-
-        if (deviceTrustLevel == null || deviceTrustLevel.getTrustLevel() == null) {
-            log.warn("No or Invalid trust level defined");
-            return;
-        }
+                CloudEventMapper.toTargetEvent(deviceHeartbeatConsumerRecord.value(), DeviceTrustLevel.class);
 
-        if (deviceTrustLevel.getTrustLevel().equals(TrustLevel.NONE)) {
-            untrustworthyCmHandlesSet.add(cmHandleId);
-            log.debug("Added cmHandleId to untrustworthy set : {}", cmHandleId);
-        } else if (deviceTrustLevel.getTrustLevel().equals(TrustLevel.COMPLETE) && untrustworthyCmHandlesSet.contains(
-                cmHandleId)) {
-            untrustworthyCmHandlesSet.remove(cmHandleId);
-            log.debug("Removed cmHandleId from untrustworthy set : {}", cmHandleId);
+        if (cmHandleId != null && deviceTrustLevel != null) {
+            final String trustLevel = deviceTrustLevel.getData().getTrustLevel();
+            trustLevelPerCmHandle.put(cmHandleId, TrustLevel.valueOf(trustLevel));
+            log.debug("Added cmHandleId to trustLevelPerCmHandle map as {}:{}", cmHandleId, trustLevel);
         }
     }
 
index f4254bb..8d1f8e9 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.trustlevel;
 
+import lombok.Getter;
+
+@Getter
 public enum TrustLevel {
-    NONE, COMPLETE;
+    NONE(0), COMPLETE(99);
+
+    private final int value;
+
+    TrustLevel(final int value) {
+        this.value = value;
+    }
+
 }
\ No newline at end of file
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelFilter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelFilter.java
new file mode 100644 (file)
index 0000000..3b704ae
--- /dev/null
@@ -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.trustlevel;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import lombok.EqualsAndHashCode;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+public class TrustLevelFilter implements Comparable<TrustLevel> {
+
+    @EqualsAndHashCode.Include
+    private final TrustLevel targetTrustLevel;
+    private final Map<String, TrustLevel> trustLevelPerCmHandle;
+
+    @Override
+    public int compareTo(@NonNull final TrustLevel other) {
+        return Integer.compare(this.targetTrustLevel.getValue(), other.getValue());
+    }
+
+    /**
+     * This method return cm handles that matches with given trust level.
+     *
+     * @return cm handle ids.
+     */
+    public Collection<String> getAllCmHandleIdsByTargetTrustLevel() {
+        final Collection<String> resultCmHandleIds = new HashSet<>();
+        trustLevelPerCmHandle.entrySet().forEach(cmHandleTrustLevelEntrySet -> {
+            if (compareTo(cmHandleTrustLevelEntrySet.getValue()) == 0) {
+                resultCmHandleIds.add(cmHandleTrustLevelEntrySet.getKey());
+            }
+        });
+        return resultCmHandleIds;
+    }
+
+}
index d3b95ea..39f8802 100644 (file)
@@ -20,7 +20,7 @@
 
 package org.onap.cps.ncmp.api.impl.trustlevel.dmiavailability;
 
-import com.hazelcast.map.IMap;
+import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
@@ -33,7 +33,7 @@ import org.springframework.stereotype.Service;
 @Service
 public class DMiPluginWatchDog {
 
-    private final IMap<String, TrustLevel> trustLevelPerDmiPlugin;
+    private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
 
     private final DmiRestClient dmiRestClient;
 
index b1bb7f7..a597760 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  Copyright (C) 2022-2023 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -29,7 +29,8 @@ import lombok.Getter;
 public enum CmHandleQueryConditions {
     HAS_ALL_PROPERTIES("hasAllProperties"),
     HAS_ALL_MODULES("hasAllModules"),
-    WITH_CPS_PATH("cmHandleWithCpsPath");
+    WITH_CPS_PATH("cmHandleWithCpsPath"),
+    WITH_TRUST_LEVEL("cmHandleWithTrustLevel");
 
     public static final Collection<String> ALL_CONDITION_NAMES = Arrays.stream(CmHandleQueryConditions.values())
         .map(CmHandleQueryConditions::getConditionName).collect(Collectors.toList());
index ce6d856..7c410cc 100644 (file)
@@ -39,7 +39,7 @@ import spock.lang.Specification
 class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
 
     def cmHandleQueries = Mock(CmHandleQueries)
-    def partiallyMockedCmHandleQueries = Spy(CmHandleQueriesImpl)
+    def partiallyMockedCmHandleQueries = Spy(CmHandleQueries)
     def mockInventoryPersistence = Mock(InventoryPersistence)
 
     def dmiRegistry = new DataNode(xpath: NCMP_DMI_REGISTRY_PARENT, childDataNodes: createDataNodeList(['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4']))
@@ -106,6 +106,17 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
             'No anchors are returned' | []
     }
 
+    def 'Query cm handles with some trust level query parameters'() {
+        given: 'a trust level condition property'
+            def trustLevelQueryParameters = new CmHandleQueryServiceParameters()
+            def trustLevelConditionProperties = createConditionProperties('cmHandleWithTrustLevel', [['trustLevel': 'COMPLETE'] as Map])
+            trustLevelQueryParameters.setCmHandleQueryParameters([trustLevelConditionProperties])
+        when: 'the query is being executed'
+            objectUnderTest.queryCmHandleIds(trustLevelQueryParameters)
+        then: 'the query is being delegated to the cm handle query service with correct parameter'
+            1 * cmHandleQueries.queryCmHandlesByTrustLevel(['trustLevel': 'COMPLETE'] as Map)
+    }
+
     def 'Query cm handle details with module names when #scenario from query.'() {
         given: 'a modules condition property'
             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
index 0d9aa61..af65cfc 100644 (file)
@@ -76,7 +76,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandleQueryService)
     def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
     def stubModuleSyncStartedOnCmHandles = Stub(IMap<String, Object>)
-    def stubTrustLevelPerDmiPlugin = Stub(IMap<String, TrustLevel>)
+    def stubTrustLevelPerDmiPlugin = Stub(Map<String, TrustLevel>)
 
     def NO_TOPIC = null
     def NO_REQUEST_ID = null
index 6184a97..3eff96d 100644 (file)
@@ -22,7 +22,6 @@ 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.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.test.context.SpringBootTest
@@ -32,7 +31,10 @@ import spock.lang.Specification
 class TrustLevelCacheConfigSpec extends Specification {
 
     @Autowired
-    private IMap<String, TrustLevel> trustLevelPerDmiPlugin
+    private Map<String, TrustLevel> trustLevelPerDmiPlugin
+
+    @Autowired
+    private Map<String, TrustLevel> trustLevelPerCmHandle
 
     def 'Hazelcast cache for trust level per dmi plugin'() {
         expect: 'system is able to create an instance of the trust level per dmi plugin cache'
@@ -43,23 +45,29 @@ class TrustLevelCacheConfigSpec extends Specification {
             assert Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceTrustLevelPerDmiPluginMap')
     }
 
-    def 'Verify Trust Level Per Dmi Plugin Cache for basic hazelcast map operations'() {
-        when: 'the key inserted into Trust Level Per Dmi Plugin Cache'
-            trustLevelPerDmiPlugin.put('dmi1', TrustLevel.COMPLETE)
-            trustLevelPerDmiPlugin.put('dmi2', TrustLevel.NONE)
-        then: 'the value for each dmi can be retrieved'
-            assert trustLevelPerDmiPlugin.get('dmi1') == TrustLevel.COMPLETE
-            assert trustLevelPerDmiPlugin.get('dmi2') == TrustLevel.NONE
+    def 'Hazelcast cache for trust level per cm handle'() {
+        expect: 'system is able to create an instance of the trust level per cm handle cache'
+            assert null != trustLevelPerCmHandle
+        and: 'there is at least 1 instance'
+            assert Hazelcast.allHazelcastInstances.size() > 0
+        and: 'Hazelcast cache instance for trust level is present'
+            assert Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceTrustLevelPerCmHandleMap')
     }
 
-    def 'Verify configs for Distributed Caches'(){
-        given: 'the Trust Level Per Dmi Plugin Cache config'
-            def trustLevelDmiPerPluginCacheConfig =  Hazelcast.getHazelcastInstanceByName('hazelcastInstanceTrustLevelPerDmiPluginMap').config
-            def trustLevelDmiPerPluginCacheMapConfig =  trustLevelDmiPerPluginCacheConfig.mapConfigs.get('trustLevelPerDmiPluginCacheConfig')
-        expect: 'system created instance with correct config'
-            assert trustLevelDmiPerPluginCacheConfig.clusterName == 'cps-and-ncmp-test-caches'
-            assert trustLevelDmiPerPluginCacheMapConfig.backupCount == 3
-            assert trustLevelDmiPerPluginCacheMapConfig.asyncBackupCount == 3
+    def 'Trust level cache configurations: #scenario'() {
+        when: 'retrieving the cache config for trustLevel'
+            def cacheConfig = Hazelcast.getHazelcastInstanceByName(hazelcastInstanceName).config
+        then: 'the cache config has the right cluster'
+            assert cacheConfig.clusterName == 'cps-and-ncmp-test-caches'
+        when: 'retrieving the map config for trustLevel'
+            def mapConfig = cacheConfig.mapConfigs.get(hazelcastMapConfigName)
+        then: 'the map config has the correct backup counts'
+            assert mapConfig.backupCount == 3
+            assert mapConfig.asyncBackupCount == 3
+        where: 'the following caches are used'
+            scenario         | hazelcastInstanceName                        | hazelcastMapConfigName
+            'cmhandle map'   | 'hazelcastInstanceTrustLevelPerCmHandleMap'  | 'trustLevelPerCmHandleCacheConfig'
+            'dmi plugin map' | 'hazelcastInstanceTrustLevelPerDmiPluginMap' | 'trustLevelPerDmiPluginCacheConfig'
     }
 
     def 'Verify deployment network configs for Distributed Caches'() {
@@ -70,6 +78,14 @@ class TrustLevelCacheConfigSpec extends Specification {
             assert !trustLevelDmiPerPluginCacheConfig.join.kubernetesConfig.enabled
     }
 
+    def 'Verify deployment network configs for Cm Handle Distributed Caches'() {
+        given: 'the Trust Level Per Cm Handle Cache config'
+            def trustLevelPerCmHandlePluginCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelcastInstanceTrustLevelPerCmHandleMap').config.networkConfig
+        expect: 'system created instance with correct config'
+            assert trustLevelPerCmHandlePluginCacheConfig.join.autoDetectionConfig.enabled
+            assert !trustLevelPerCmHandlePluginCacheConfig.join.kubernetesConfig.enabled
+    }
+
     def 'Verify network config'() {
         given: 'Synchronization config object and test configuration'
             def objectUnderTest = new TrustLevelCacheConfig()
index 380aea4..e6d3831 100644 (file)
@@ -34,17 +34,30 @@ class CloudEventMapperSpec extends Specification {
     @Autowired
     JsonObjectMapper jsonObjectMapper
 
-    def 'Cloud event to Target event type when it is #scenario'() {
-        expect: 'Events mapped correctly'
-            assert mappedCloudEvent == (CloudEventMapper.toTargetEvent(testCloudEvent(), targetClass) != null)
+    def 'Cloud event to target event type'() {
+        given: 'a cloud event with valid payload'
+            def cloudEvent = testCloudEvent(new CmSubscriptionNcmpInEvent())
+        when: 'the cloud event mapped to target event'
+            def result = CloudEventMapper.toTargetEvent((cloudEvent), CmSubscriptionNcmpInEvent.class)
+        then: 'the cloud event is mapped'
+            assert result instanceof CmSubscriptionNcmpInEvent
+    }
+
+    def 'Cloud event to target event type when it is #scenario'() {
+        given: 'a cloud event with invalid payload'
+            def cloudEvent = testCloudEvent(payload)
+        when: 'the cloud event mapped to target event'
+            def result = CloudEventMapper.toTargetEvent(cloudEvent, CmSubscriptionNcmpInEvent.class)
+        then: 'result is null'
+            assert result == null
         where: 'below are the scenarios'
-            scenario                | targetClass                     || mappedCloudEvent
-            'valid concrete type'   | CmSubscriptionNcmpInEvent.class || true
-            'invalid concrete type' | ArrayList.class                 || false
+            scenario               | payload
+            'invalid payload type' | ArrayList.class
+            'without payload'      | null
     }
 
-    def testCloudEvent() {
-        return CloudEventBuilder.v1().withData(jsonObjectMapper.asJsonBytes(new CmSubscriptionNcmpInEvent()))
+    def testCloudEvent(payload) {
+        return CloudEventBuilder.v1().withData(jsonObjectMapper.asJsonBytes(payload))
             .withId("cmhandle1")
             .withSource(URI.create('test-source'))
             .withDataSchema(URI.create('test'))
index 48de23d..80778b9 100644 (file)
 package org.onap.cps.ncmp.api.impl.trustlevel
 
 import com.fasterxml.jackson.databind.ObjectMapper
-import com.hazelcast.collection.ISet
+import com.hazelcast.map.IMap
 import io.cloudevents.CloudEvent
 import io.cloudevents.core.builder.CloudEventBuilder
 import org.apache.kafka.clients.consumer.ConsumerRecord
+import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel
 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 = [ObjectMapper, JsonObjectMapper])
 class DeviceHeartbeatConsumerSpec extends Specification {
 
-    def mockUntrustworthyCmHandlesSet = Mock(ISet<String>)
+    def mockTrustLevelPerCmHandle = Mock(Map<String, TrustLevel>)
+
+    def objectUnderTest = new DeviceHeartbeatConsumer(mockTrustLevelPerCmHandle)
     def objectMapper = new ObjectMapper()
 
-    def objectUnderTest = new DeviceHeartbeatConsumer(mockUntrustworthyCmHandlesSet)
+    @Autowired
+    JsonObjectMapper jsonObjectMapper
+
+    def static trustLevelString = '{"data":{"trustLevel": "COMPLETE"}}'
 
-    def 'Operations to be done in an empty untrustworthy set for #scenario'() {
-        given: 'an event with trustlevel as #trustLevel'
-            def incomingEvent = testCloudEvent(trustLevel)
-        and: 'transformed as a kafka record'
-            def consumerRecord = new ConsumerRecord<String, CloudEvent>('test-device-heartbeat', 0, 0, 'cmhandle1', incomingEvent)
+    def 'Consume a trustlevel event'() {
+        given: 'an event from dmi with trust level complete'
+            def payload = jsonObjectMapper.convertJsonString(trustLevelString, DeviceTrustLevel.class)
+            def eventFromDmi = createTrustLevelEvent(payload)
+        and: 'transformed to a consumer record with a cloud event id (ce_id)'
+            def consumerRecord = new ConsumerRecord<String, CloudEvent>('test-device-heartbeat', 0, 0, 'sample-message-key', eventFromDmi)
             consumerRecord.headers().add('ce_id', objectMapper.writeValueAsBytes('cmhandle1'))
         when: 'the event is consumed'
             objectUnderTest.heartbeatListener(consumerRecord)
-        then: 'untrustworthy cmhandles are stored'
-            untrustworthyCmHandlesSetInvocationForAdd * mockUntrustworthyCmHandlesSet.add(_)
-        and: 'trustworthy cmHandles will be removed from untrustworthy set'
-            untrustworthyCmHandlesSetInvocationForContains * mockUntrustworthyCmHandlesSet.contains(_)
-
-        where: 'below scenarios are applicable'
-            scenario         | trustLevel          || untrustworthyCmHandlesSetInvocationForAdd | untrustworthyCmHandlesSetInvocationForContains
-            'None trust'     | TrustLevel.NONE     || 1                                         | 0
-            'Complete trust' | TrustLevel.COMPLETE || 0                                         | 1
+        then: 'cm handles are stored with correct trust level'
+            1 * mockTrustLevelPerCmHandle.put('"cmhandle1"', TrustLevel.COMPLETE)
     }
 
-    def 'Invalid trust'() {
-        when: 'we provide an invalid trust in the event'
-            def consumerRecord = new ConsumerRecord<String, CloudEvent>('test-device-heartbeat', 0, 0, 'cmhandle1', testCloudEvent(null))
-            consumerRecord.headers().add('ce_id', objectMapper.writeValueAsBytes('cmhandle1'))
+    def 'Consume trustlevel event without cloud event id'() {
+        given: 'an event from dmi'
+            def payload = jsonObjectMapper.convertJsonString(trustLevelString, DeviceTrustLevel.class)
+            def eventFromDmi = createTrustLevelEvent(payload)
+        and: 'transformed to a consumer record WITHOUT Cloud event ID (ce_id)'
+            def consumerRecord = new ConsumerRecord<String, CloudEvent>('test-device-heartbeat', 0, 0, 'sample-message-key', eventFromDmi)
+        when: 'the event is consumed'
             objectUnderTest.heartbeatListener(consumerRecord)
-        then: 'no interaction with the untrustworthy cmhandles set'
-            0 * mockUntrustworthyCmHandlesSet.add(_)
-            0 * mockUntrustworthyCmHandlesSet.contains(_)
-            0 * mockUntrustworthyCmHandlesSet.remove(_)
-        and: 'control flow returns without any exception'
-            noExceptionThrown()
-
+        then: 'no cm handle has been stored in the map'
+            0 * mockTrustLevelPerCmHandle.put(*_)
     }
 
-    def 'Remove trustworthy cmhandles from untrustworthy cmhandles set'() {
-        given: 'an event with COMPLETE trustlevel'
-            def incomingEvent = testCloudEvent(TrustLevel.COMPLETE)
-        and: 'transformed as a kafka record'
-            def consumerRecord = new ConsumerRecord<String, CloudEvent>('test-device-heartbeat', 0, 0, 'cmhandle1', incomingEvent)
-            consumerRecord.headers().add('ce_id', objectMapper.writeValueAsBytes('cmhandle1'))
-        and: 'untrustworthy cmhandles set contains cmhandle1'
-            1 * mockUntrustworthyCmHandlesSet.contains(_) >> true
+    def 'Consume a trust level event without payload'() {
+        given: 'a consumer record with ce_id header but without payload'
+            def consumerRecord = new ConsumerRecord<String, CloudEvent>('test-device-heartbeat', 0, 0, 'cmhandle1', createTrustLevelEvent(null))
+            consumerRecord.headers().add('some_other_header_value', objectMapper.writeValueAsBytes('cmhandle1'))
         when: 'the event is consumed'
             objectUnderTest.heartbeatListener(consumerRecord)
-        then: 'cmhandle removed from untrustworthy cmhandles set'
-            1 * mockUntrustworthyCmHandlesSet.remove(_) >> {
-                args ->
-                    {
-                        args[0].equals('cmhandle1')
-                    }
-            }
-
+        then: 'no cm handle has been stored in the map'
+            0 * mockTrustLevelPerCmHandle.put(*_)
     }
 
-    def testCloudEvent(trustLevel) {
-        return CloudEventBuilder.v1().withData(objectMapper.writeValueAsBytes(new DeviceTrustLevel(trustLevel)))
+    def createTrustLevelEvent(eventPayload) {
+        return CloudEventBuilder.v1().withData(objectMapper.writeValueAsBytes(eventPayload))
             .withId("cmhandle1")
             .withSource(URI.create('DMI'))
             .withDataSchema(URI.create('test'))
-            .withType('org.onap.cm.events.trustlevel-notification')
+            .withType('org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel')
             .build()
     }
 
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.impl.trustlevel;
+package org.onap.cps.ncmp.api.impl.trustlevel
 
-import java.io.Serializable;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
 
-@AllArgsConstructor
-@Data
-@NoArgsConstructor
-class DeviceTrustLevel implements Serializable {
+import spock.lang.Specification
 
-    private static final long serialVersionUID = -1705715024067165212L;
+class TrustLevelFilterSpec extends Specification {
 
-    private TrustLevel trustLevel;
+    def targetTrustLevel = TrustLevel.COMPLETE
 
+    def trustLevelPerCmHandle = [ 'my completed cm handle': TrustLevel.COMPLETE, 'my untrusted cm handle': TrustLevel.NONE ]
+
+    def objectUnderTest = new TrustLevelFilter(targetTrustLevel, trustLevelPerCmHandle)
+
+    def 'Obtain cm handle ids by a given trust level value'() {
+        when: 'cm handles are retrieved'
+            def result = objectUnderTest.getAllCmHandleIdsByTargetTrustLevel()
+        then: 'the result only contains the completed cm handle'
+            assert result.size() == 1
+            assert result[0] == 'my completed cm handle'
+    }
 }
index af546b7..b6259bd 100644 (file)
@@ -20,7 +20,6 @@
 
 package org.onap.cps.ncmp.api.impl.trustlevel.dmiavailability
 
-import com.hazelcast.map.IMap
 import org.onap.cps.ncmp.api.impl.client.DmiRestClient
 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
 import spock.lang.Specification
@@ -28,7 +27,7 @@ import spock.lang.Specification
 class DMiPluginWatchDogSpec extends Specification {
 
 
-    def mockTrustLevelPerDmiPlugin = Mock(IMap<String, TrustLevel>)
+    def mockTrustLevelPerDmiPlugin = Mock(Map<String, TrustLevel>)
     def mockDmiRestClient = Mock(DmiRestClient)
     def objectUnderTest = new DMiPluginWatchDog(mockTrustLevelPerDmiPlugin, mockDmiRestClient)
 
index f0e2d9f..100705f 100644 (file)
@@ -26,10 +26,11 @@ class CmHandleQueryConditionsSpec extends Specification {
 
     def 'CmHandle query condition names.'() {
         expect: '3 conditions with the correct names'
-            assert CmHandleQueryConditions.ALL_CONDITION_NAMES.size() == 3
+            assert CmHandleQueryConditions.ALL_CONDITION_NAMES.size() == 4
             assert CmHandleQueryConditions.ALL_CONDITION_NAMES.containsAll('hasAllProperties',
                                                                            'hasAllModules',
-                                                                           'cmHandleWithCpsPath')
+                                                                           'cmHandleWithCpsPath',
+                                                                            'cmHandleWithTrustLevel')
     }
 
 }
index e7c337c..a3a5efc 100644 (file)
 
 package org.onap.cps.ncmp.api.inventory
 
+import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
+
 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 
+import com.hazelcast.map.IMap
 import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueriesImpl
 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
 import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
@@ -37,8 +40,9 @@ import spock.lang.Specification
 
 class CmHandleQueriesImplSpec extends Specification {
     def cpsDataPersistenceService = Mock(CpsDataPersistenceService)
+    def trustLevelPerCmHandle = [ 'my completed cm handle': TrustLevel.COMPLETE, 'my untrusted cm handle': TrustLevel.NONE ]
 
-    def objectUnderTest = new CmHandleQueriesImpl(cpsDataPersistenceService)
+    def objectUnderTest = new CmHandleQueriesImpl(cpsDataPersistenceService, trustLevelPerCmHandle)
 
     @Shared
     def static sampleDataNodes = [new DataNode()]
@@ -60,11 +64,21 @@ class CmHandleQueriesImplSpec extends Specification {
             result.containsAll(expectedCmHandleIds)
             result.size() == expectedCmHandleIds.size()
         where: 'the following data is used'
-            scenario                         | publicPropertyPairs                                                                           || expectedCmHandleIds
-            'single property matches'        | ['Contact' : 'newemailforstore@bookstore.com']                                                || ['PNFDemo', 'PNFDemo2', 'PNFDemo4']
-            'public property does not match' | ['wont_match' : 'wont_match']                                                                 || []
-            '2 properties, only one match'   | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': 'newemailforstore2@bookstore.com'] || ['PNFDemo4']
-            '2 properties, no matches'       | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': '']                                || []
+            scenario                         | publicPropertyPairs                                                                      || expectedCmHandleIds
+            'single property matches'        | [Contact: 'newemailforstore@bookstore.com']                                              || ['PNFDemo', 'PNFDemo2', 'PNFDemo4']
+            'public property does not match' | [wont_match: 'wont_match']                                                               || []
+            '2 properties, only one match'   | [Contact: 'newemailforstore@bookstore.com', Contact2: 'newemailforstore2@bookstore.com'] || ['PNFDemo4']
+            '2 properties, no matches'       | [Contact: 'newemailforstore@bookstore.com', Contact2: '']                                || []
+    }
+
+    def 'Query cm handles on trust level'() {
+        given: 'query properties for trustlevel COMPLETE'
+            def trustLevelPropertyQueryPairs = ['trustLevel' : TrustLevel.COMPLETE.toString()]
+        when: 'the query is executed'
+            def result = objectUnderTest.queryCmHandlesByTrustLevel(trustLevelPropertyQueryPairs)
+        then: 'the result only contains the completed cm handle'
+            assert result.size() == 1
+            assert result[0] == 'my completed cm handle'
     }
 
     def 'Query CmHandles using empty public properties query pair.'() {