Merge "Trust level updates with dmi status change"
authorToine Siebelink <toine.siebelink@est.tech>
Fri, 17 Nov 2023 11:09:08 +0000 (11:09 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 17 Nov 2023 11:09:08 +0000 (11:09 +0000)
12 files changed:
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/NetworkCmProxyDataServicePropertyHandler.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/inventory/CmHandleQueriesImpl.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 [deleted file]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginStatus.java [deleted file]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DMiPluginWatchDog.java with 64% similarity]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelTest.groovy [moved from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelFilterSpec.groovy with 50% similarity]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy [moved from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DMiPluginWatchDogSpec.groovy with 52% similarity]

index 1f87a1e..db7b12c 100755 (executable)
@@ -105,7 +105,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     @Override
     public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
-            final DmiPluginRegistration dmiPluginRegistration) {
+        final DmiPluginRegistration dmiPluginRegistration) {
         dmiPluginRegistration.validateDmiPluginRegistration();
         final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
 
@@ -113,23 +113,23 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
         if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setRemovedCmHandles(
-                    parseAndProcessDeletedCmHandlesInRegistration(dmiPluginRegistration.getRemovedCmHandles()));
+                parseAndProcessDeletedCmHandlesInRegistration(dmiPluginRegistration.getRemovedCmHandles()));
         }
 
         if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setCreatedCmHandles(
-                    parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration));
+                parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration));
             populateTrustLevelPerCmHandleCache(dmiPluginRegistration);
         }
         if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setUpdatedCmHandles(
-                    networkCmProxyDataServicePropertyHandler
-                            .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
+                networkCmProxyDataServicePropertyHandler
+                    .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
         }
         if (dmiPluginRegistration.getUpgradedCmHandles() != null
-                && !dmiPluginRegistration.getUpgradedCmHandles().getCmHandles().isEmpty()) {
+            && !dmiPluginRegistration.getUpgradedCmHandles().getCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setUpgradedCmHandles(
-                    parseAndProcessUpgradedCmHandlesInRegistration(dmiPluginRegistration));
+                parseAndProcessUpgradedCmHandlesInRegistration(dmiPluginRegistration));
         }
 
         return dmiPluginRegistrationResponse;
@@ -143,10 +143,10 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
                                              final String topicParamInQuery,
                                              final String requestId) {
         final ResponseEntity<?> responseEntity = dmiDataOperations.getResourceDataFromDmi(datastoreName, cmHandleId,
-                resourceIdentifier,
-                optionsParamInQuery,
-                topicParamInQuery,
-                requestId);
+            resourceIdentifier,
+            optionsParamInQuery,
+            topicParamInQuery,
+            requestId);
         return responseEntity.getBody();
     }
 
@@ -156,13 +156,13 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
                                              final String resourceIdentifier,
                                              final FetchDescendantsOption fetchDescendantsOption) {
         return cpsDataService.getDataNodes(datastoreName, cmHandleId, resourceIdentifier,
-                fetchDescendantsOption).iterator().next();
+            fetchDescendantsOption).iterator().next();
     }
 
     @Override
     public void executeDataOperationForCmHandles(final String topicParamInQuery,
                                                  final DataOperationRequest
-                                                         dataOperationRequest,
+                                                     dataOperationRequest,
                                                  final String requestId) {
         dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId);
     }
@@ -174,7 +174,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
                                                                  final String requestData,
                                                                  final String dataType) {
         return dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(cmHandleId, resourceIdentifier,
-                operationType, requestData, dataType);
+            operationType, requestData, dataType);
     }
 
     @Override
@@ -195,9 +195,9 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      */
     @Override
     public Collection<NcmpServiceCmHandle> executeCmHandleSearch(
-            final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
+        final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
         final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
-                cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
+            cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
         validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
         return networkCmProxyCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters);
     }
@@ -211,7 +211,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     @Override
     public Collection<String> executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
         final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
-                cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
+            cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
         validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
         return networkCmProxyCmHandleQueryService.queryCmHandleIds(cmHandleQueryServiceParameters);
     }
@@ -220,7 +220,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      * Set the data sync enabled flag, along with the data sync state
      * based on the data sync enabled boolean for the cm handle id provided.
      *
-     * @param cmHandleId      cm handle id
+     * @param cmHandleId                 cm handle id
      * @param dataSyncEnabledTargetValue data sync enabled flag
      */
     @Override
@@ -232,18 +232,18 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         }
         if (CmHandleState.READY.equals(compositeState.getCmHandleState())) {
             final DataStoreSyncState dataStoreSyncState = compositeState.getDataStores()
-                    .getOperationalDataStore().getDataStoreSyncState();
+                .getOperationalDataStore().getDataStoreSyncState();
             if (Boolean.FALSE.equals(dataSyncEnabledTargetValue)
-                    && DataStoreSyncState.SYNCHRONIZED.equals(dataStoreSyncState)) {
+                && DataStoreSyncState.SYNCHRONIZED.equals(dataStoreSyncState)) {
                 // TODO : This is hard-coded for onap dmi that need to be addressed
                 cpsDataService.deleteDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId,
-                        "/netconf-state", OffsetDateTime.now());
+                    "/netconf-state", OffsetDateTime.now());
             }
             CompositeStateUtils.setDataSyncEnabledFlagWithDataSyncState(dataSyncEnabledTargetValue, compositeState);
             inventoryPersistence.saveCmHandleState(cmHandleId, compositeState);
         } else {
             throw new CpsException("State mismatch exception.", "Cm-Handle not in READY state. Cm handle state is: "
-                    + compositeState.getCmHandleState());
+                + compositeState.getCmHandleState());
         }
     }
 
@@ -266,7 +266,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      */
     @Override
     public Collection<String> executeCmHandleIdSearchForInventory(
-            final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
+        final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
         validateCmHandleQueryParameters(cmHandleQueryServiceParameters, InventoryQueryConditions.ALL_CONDITION_NAMES);
         return networkCmProxyCmHandleQueryService.queryCmHandleIdsForInventory(cmHandleQueryServiceParameters);
     }
@@ -280,7 +280,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     @Override
     public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleId) {
         return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(
-                inventoryPersistence.getYangModelCmHandle(cmHandleId));
+            inventoryPersistence.getYangModelCmHandle(cmHandleId));
     }
 
     /**
@@ -316,27 +316,26 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      * @return cm-handle registration response for create cm-handle requests.
      */
     public List<CmHandleRegistrationResponse> parseAndProcessCreatedCmHandlesInRegistration(
-            final DmiPluginRegistration dmiPluginRegistration) {
+        final DmiPluginRegistration dmiPluginRegistration) {
         final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle = new HashMap<>();
-        dmiPluginRegistration.getCreatedCmHandles()
-                .forEach(cmHandle -> {
-                    final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(
-                            dmiPluginRegistration.getDmiPlugin(),
-                            dmiPluginRegistration.getDmiDataPlugin(),
-                            dmiPluginRegistration.getDmiModelPlugin(),
-                            cmHandle,
-                            cmHandle.getModuleSetTag());
-                    cmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.ADVISED);
-                });
+        dmiPluginRegistration.getCreatedCmHandles().forEach(cmHandle -> {
+            final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(
+                dmiPluginRegistration.getDmiPlugin(),
+                dmiPluginRegistration.getDmiDataPlugin(),
+                dmiPluginRegistration.getDmiModelPlugin(),
+                cmHandle,
+                cmHandle.getModuleSetTag());
+            cmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.ADVISED);
+        });
         return registerNewCmHandles(cmHandleStatePerCmHandle);
     }
 
     protected List<CmHandleRegistrationResponse> parseAndProcessDeletedCmHandlesInRegistration(
-            final List<String> tobeRemovedCmHandles) {
+        final List<String> tobeRemovedCmHandles) {
         final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
-                new ArrayList<>(tobeRemovedCmHandles.size());
+            new ArrayList<>(tobeRemovedCmHandles.size());
         final Collection<YangModelCmHandle> yangModelCmHandles =
-                inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles);
+            inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles);
 
         updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING);
 
@@ -367,7 +366,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     }
 
     protected List<CmHandleRegistrationResponse> parseAndProcessUpgradedCmHandlesInRegistration(
-            final DmiPluginRegistration dmiPluginRegistration) {
+        final DmiPluginRegistration dmiPluginRegistration) {
 
         final List<String> upgradedCmHandleIds = dmiPluginRegistration.getUpgradedCmHandles().getCmHandles();
 
@@ -446,7 +445,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     private void deleteCmHandleFromDbAndModuleSyncMap(final String cmHandleId) {
         inventoryPersistence.deleteSchemaSetWithCascade(cmHandleId);
         inventoryPersistence.deleteDataNode(NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId
-                + "']");
+            + "']");
         removeDeletedCmHandleFromModuleSyncMap(cmHandleId);
     }
 
@@ -458,8 +457,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private Collection<String> mapCmHandleIdsToXpaths(final Collection<String> cmHandles) {
         return cmHandles.stream()
-                .map(cmHandleId -> NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']")
-                .collect(Collectors.toSet());
+            .map(cmHandleId -> NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']")
+            .collect(Collectors.toSet());
     }
 
     // CPS-1239 Robustness cleaning of in progress cache
@@ -470,7 +469,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     }
 
     private List<CmHandleRegistrationResponse> registerNewCmHandles(final Map<YangModelCmHandle, CmHandleState>
-                                                                            cmHandleStatePerCmHandle) {
+                                                                        cmHandleStatePerCmHandle) {
         final List<String> cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle);
         try {
             lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle);
@@ -495,7 +494,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     }
 
     private List<CmHandleRegistrationResponse> upgradeCmHandles(final Map<YangModelCmHandle, CmHandleState>
-                                                                        cmHandleStatePerCmHandle) {
+                                                                    cmHandleStatePerCmHandle) {
         final List<String> cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle);
         log.info("Moving cm handles : {} into locked (for upgrade) state.", cmHandleIds);
         try {
index 25ded16..be6a401 100644 (file)
@@ -74,8 +74,8 @@ public class NetworkCmProxyDataServicePropertyHandler {
                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId));
             } catch (final DataNodeNotFoundException e) {
                 log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, e.getMessage());
-                cmHandleRegistrationResponses.add(CmHandleRegistrationResponse
-                    .createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
+                cmHandleRegistrationResponses.add(
+                    CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
             } catch (final DataValidationException e) {
                 log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage());
                 cmHandleRegistrationResponses.add(
index 4ef4003..b6eb092 100644 (file)
 package org.onap.cps.ncmp.api.impl.client;
 
 import com.fasterxml.jackson.databind.JsonNode;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties;
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException;
 import org.onap.cps.ncmp.api.impl.operations.OperationType;
-import org.onap.cps.ncmp.api.impl.trustlevel.dmiavailability.DmiPluginStatus;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
@@ -37,19 +36,21 @@ import org.springframework.web.client.HttpStatusCodeException;
 import org.springframework.web.client.RestTemplate;
 
 @Component
-@AllArgsConstructor
+@RequiredArgsConstructor
 @Slf4j
 public class DmiRestClient {
 
     private static final String HEALTH_CHECK_URL_EXTENSION = "/actuator/health";
-    private RestTemplate restTemplate;
-    private DmiProperties dmiProperties;
+    private static final String EMPTY_STRING = "";
+    private final RestTemplate restTemplate;
+    private final DmiProperties dmiProperties;
 
     /**
      * Sends POST operation to DMI with json body containing module references.
-     * @param dmiResourceUrl dmi resource url
+     *
+     * @param dmiResourceUrl          dmi resource url
      * @param requestBodyAsJsonString json data body
-     * @param operationType the type of operation being executed (for error reporting only)
+     * @param operationType           the type of operation being executed (for error reporting only)
      * @return response entity of type String
      */
     public ResponseEntity<Object> postOperationWithJsonData(final String dmiResourceUrl,
@@ -61,28 +62,28 @@ public class DmiRestClient {
         } catch (final HttpStatusCodeException httpStatusCodeException) {
             final String exceptionMessage = "Unable to " + operationType.toString() + " resource data.";
             throw new HttpClientRequestException(exceptionMessage, httpStatusCodeException.getResponseBodyAsString(),
-                    httpStatusCodeException.getStatusCode().value());
+                httpStatusCodeException.getStatusCode().value());
         }
     }
 
     /**
-     * Sends GET operation to DMI plugin's health check URL.
+     * Get DMI plugin health status.
      *
      * @param       dmiPluginBaseUrl the base URL of the dmi-plugin
-     * @return      DmiPluginStatus as UP or DOWN
+     * @return      plugin health status ("UP" is all OK, EMPTY_STRING in case of any exception)
      */
-    public DmiPluginStatus getDmiPluginStatus(final String dmiPluginBaseUrl) {
+    public String getDmiHealthStatus(final String dmiPluginBaseUrl) {
+        final HttpEntity<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders()));
         try {
-            final HttpEntity<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders()));
-            final JsonNode dmiPluginHealthStatus = restTemplate
-                .getForObject(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION, JsonNode.class, httpHeaders);
-            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());
+            final JsonNode responseHealthStatus =
+                restTemplate.getForObject(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION,
+                JsonNode.class, httpHeaders);
+            return responseHealthStatus == null ? EMPTY_STRING :
+                responseHealthStatus.get("status").asText();
+        } catch (final Exception e) {
+            log.warn("Failed to retrieve health status from {}. Error Message: {}", dmiPluginBaseUrl, e.getMessage());
+            return EMPTY_STRING;
         }
-        return DmiPluginStatus.DOWN;
     }
 
     private HttpHeaders configureHttpHeaders(final HttpHeaders httpHeaders) {
index 419d0a3..2d7ad69 100644 (file)
@@ -36,7 +36,6 @@ 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;
@@ -50,6 +49,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
     private static final String DESCENDANT_PATH = "//";
     private static final String ANCESTOR_CM_HANDLES = "/ancestor::cm-handles";
     private final CpsDataPersistenceService cpsDataPersistenceService;
+    private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
     private final Map<String, TrustLevel> trustLevelPerCmHandle;
     private final CpsValidator cpsValidator;
 
@@ -68,8 +68,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
         final String trustLevelProperty = trustLevelPropertyQueryPairs.values().iterator().next();
         final TrustLevel targetTrustLevel = TrustLevel.valueOf(trustLevelProperty);
 
-        final TrustLevelFilter trustLevelFilter = new TrustLevelFilter(targetTrustLevel, trustLevelPerCmHandle);
-        return trustLevelFilter.getAllCmHandleIdsByTargetTrustLevel();
+        return getCmHandleIdsByTrustLevel(targetTrustLevel);
     }
 
     @Override
@@ -117,6 +116,26 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
         return cmHandleIds;
     }
 
+    private Collection<String> getCmHandleIdsByTrustLevel(final TrustLevel targetTrustLevel) {
+        final Collection<String> selectedCmHandleIds = new HashSet<>();
+
+        for (final Map.Entry<String, TrustLevel> mapEntry : trustLevelPerDmiPlugin.entrySet()) {
+            final String dmiPluginIdentifier = mapEntry.getKey();
+            final TrustLevel dmiTrustLevel = mapEntry.getValue();
+            final Collection<String> candidateCmHandleIds = getCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifier);
+            for (final String candidateCmHandleId : candidateCmHandleIds) {
+                final TrustLevel candidateCmHandleTrustLevel = trustLevelPerCmHandle.get(candidateCmHandleId);
+                final TrustLevel effectiveTrustlevel =
+                    candidateCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
+                if (targetTrustLevel.equals(effectiveTrustlevel)) {
+                    selectedCmHandleIds.add(candidateCmHandleId);
+                }
+            }
+        }
+
+        return selectedCmHandleIds;
+    }
+
     private Collection<String> collectCmHandleIdsFromDataNodes(final Collection<DataNode> dataNodes) {
         return dataNodes.stream().map(dataNode -> (String) dataNode.getLeaves().get("id")).collect(Collectors.toSet());
     }
index 8d1f8e9..f130604 100644 (file)
@@ -25,11 +25,28 @@ import lombok.Getter;
 @Getter
 public enum TrustLevel {
     NONE(0), COMPLETE(99);
+    private final int level;
 
-    private final int value;
+    /**
+     * Creates TrustLevel enum from a numeric value.
+     *
+     * @param       level numeric value between 0-99
+     */
+    TrustLevel(final int level) {
+        this.level = level;
+    }
 
-    TrustLevel(final int value) {
-        this.value = value;
+    /**
+     * Gets the lower trust level (effective) among two.
+     *
+     * @param       other the trust level compared with this
+     * @return      the lower trust level
+     */
+    public final TrustLevel getEffectiveTrustLevel(final TrustLevel other) {
+        if (other.level < this.level) {
+            return other;
+        }
+        return this;
     }
 
-}
\ 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
deleted file mode 100644 (file)
index 3b704ae..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation
- *  ================================================================================
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *  SPDX-License-Identifier: Apache-2.0
- *  ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.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;
-    }
-
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginStatus.java
deleted file mode 100644 (file)
index 352d36f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation
- *  ================================================================================
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *  SPDX-License-Identifier: Apache-2.0
- *  ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.trustlevel.dmiavailability;
-
-public enum DmiPluginStatus {
-    UP, DOWN;
-}
@@ -31,28 +31,24 @@ import org.springframework.stereotype.Service;
 @Slf4j
 @RequiredArgsConstructor
 @Service
-public class DMiPluginWatchDog {
-
-    private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
+public class DmiPluginWatchDog {
 
     private final DmiRestClient dmiRestClient;
+    private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
 
     /**
-     * Monitors the aliveness of DMI plugins by this watchdog.
-     * This method periodically checks the health and status of each DMI plugin to ensure that
-     * they are functioning properly. If a plugin is found to be unresponsive or in an
-     * unhealthy state, the cache will be updated with the latest status.
-     * The @fixedDelayString is the time interval, in milliseconds, between consecutive aliveness checks.
+     * This class monitors the trust level of all DMI plugin by checking the health status
+     * the resulting trustlevel wil be stored in the relevant cache.
+     * The @fixedDelayString is the time interval, in milliseconds, between consecutive checks.
      */
     @Scheduled(fixedDelayString = "${ncmp.timers.trust-evel.dmi-availability-watchdog-ms:30000}")
-    public void watchDmiPluginAliveness() {
-        trustLevelPerDmiPlugin.keySet().forEach(dmiPluginName -> {
-            final DmiPluginStatus dmiPluginStatus = dmiRestClient.getDmiPluginStatus(dmiPluginName);
-            log.debug("Trust level for dmi-plugin: {} is {}", dmiPluginName, dmiPluginStatus.toString());
-            if (DmiPluginStatus.UP.equals(dmiPluginStatus)) {
-                trustLevelPerDmiPlugin.put(dmiPluginName, TrustLevel.COMPLETE);
+    public void watchDmiPluginTrustLevel() {
+        trustLevelPerDmiPlugin.keySet().forEach(dmiKey -> {
+            final String dmiHealthStatus = dmiRestClient.getDmiHealthStatus(dmiKey);
+            if ("UP".equals(dmiHealthStatus)) {
+                trustLevelPerDmiPlugin.put(dmiKey, TrustLevel.COMPLETE);
             } else {
-                trustLevelPerDmiPlugin.put(dmiPluginName, TrustLevel.NONE);
+                trustLevelPerDmiPlugin.put(dmiKey, TrustLevel.NONE);
             }
         });
     }
index 80c0a27..c9ba564 100644 (file)
@@ -25,8 +25,8 @@ import com.fasterxml.jackson.databind.JsonNode
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.databind.node.ObjectNode
 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties;
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
-import org.onap.cps.ncmp.api.impl.trustlevel.dmiavailability.DmiPluginStatus
 import org.onap.cps.ncmp.utils.TestUtils
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
@@ -45,35 +45,30 @@ import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
 
 @SpringBootTest
-@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiRestClient, ObjectMapper])
+@ContextConfiguration(classes = [DmiProperties, DmiRestClient, ObjectMapper])
 class DmiRestClientSpec extends Specification {
 
     @SpringBean
     RestTemplate mockRestTemplate = Mock(RestTemplate)
 
+    @Autowired
+    NcmpConfiguration.DmiProperties dmiProperties
+
     @Autowired
     DmiRestClient objectUnderTest
 
     @Autowired
     ObjectMapper objectMapper
 
-    def resourceUrl = 'some url'
-    def mockResponseEntity = Mock(ResponseEntity)
-    def dmiProperties = new NcmpConfiguration.DmiProperties()
-
-    def setup() {
-        dmiProperties.authUsername = 'test user'
-        dmiProperties.authPassword = 'test pass'
-        dmiProperties.dmiBasePath = 'dmi'
-    }
+    def responseFromRestTemplate = Mock(ResponseEntity)
 
     def 'DMI POST operation with JSON.'() {
-        given: 'the rest template returns a valid response entity'
-            mockRestTemplate.postForEntity(resourceUrl, _ as HttpEntity, Object.class) >> mockResponseEntity
+        given: 'the rest template returns a valid response entity for the expected parameters'
+            mockRestTemplate.postForEntity('my url', _ as HttpEntity, Object.class) >> responseFromRestTemplate
         when: 'POST operation is invoked'
-            def result = objectUnderTest.postOperationWithJsonData(resourceUrl, 'json-data', READ)
+            def result = objectUnderTest.postOperationWithJsonData('my url', 'some json', READ)
         then: 'the output of the method is equal to the output from the test template'
-            result == mockResponseEntity
+            result == responseFromRestTemplate
     }
 
     def 'Failing DMI POST operation.'() {
@@ -93,40 +88,34 @@ class DmiRestClientSpec extends Specification {
             operation << [CREATE, READ, PATCH]
     }
 
-    def 'Get dmi plugin health status #scenario'() {
-        given: 'a health check response data as jsonNode'
+    def 'Dmi trust level is determined by spring boot health status'() {
+        given: 'a health check response'
             def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json')
             def jsonNode = objectMapper.readValue(dmiPluginHealthCheckResponseJsonData, JsonNode.class)
-            ((ObjectNode) jsonNode).put('status', dmiAliveness);
-        and: 'the rest template return a valid json node'
+            ((ObjectNode) jsonNode).put('status', 'my status')
             mockRestTemplate.getForObject(*_) >> {jsonNode}
-        when: 'get aliveness of the dmi plugin'
-            def result = objectUnderTest.getDmiPluginStatus(resourceUrl)
-        then: 'return value is equal to result of rest template call'
-            result == expectedResult
-        where: 'the following dmi aliveness are being used'
-            scenario             | dmiAliveness || expectedResult
-            'dmi plugin is UP'   | 'UP'         || DmiPluginStatus.UP
-            'dmi plugin is DOWN' | 'DOWN'       || DmiPluginStatus.DOWN
+        when: 'get trust level of the dmi plugin'
+            def result = objectUnderTest.getDmiHealthStatus('some url')
+        then: 'the correct trust level is returned'
+            assert result == 'my status'
     }
 
     def 'Failing to get dmi plugin health status #scenario'() {
-        given: 'the rest template return null'
-            mockRestTemplate.getForObject(*_) >> {getResponse}
-        when: 'get aliveness of the dmi plugin'
-            def result = objectUnderTest.getDmiPluginStatus(resourceUrl)
-        then: 'return value is equal to result of rest template call'
-            result == expectedResult
-        where: 'the following dmi responses are being used'
-            scenario                        | getResponse                  || expectedResult
-            'get response is null'          | null                         || DmiPluginStatus.DOWN
-            'get response throws exception' | {throw new Exception()}      || DmiPluginStatus.DOWN
+        given: 'rest template with #scenario'
+            mockRestTemplate.getForObject(*_) >> healthStatusResponse
+        when: 'attempt to get health status of the dmi plugin'
+            def result = objectUnderTest.getDmiHealthStatus('some url')
+        then: 'result will be EMPTY_STRING "" '
+            assert result == ''
+        where: 'the following values are used'
+            scenario    | healthStatusResponse
+            'null'      | null
+            'exception' | {throw new Exception()}
     }
 
     def 'Basic auth header #scenario'() {
         when: 'Specific dmi properties are provided'
             dmiProperties.dmiBasicAuthEnabled = authEnabled
-            objectUnderTest.dmiProperties = dmiProperties
         then: 'http headers to conditionally have Authorization header'
             assert (objectUnderTest.configureHttpHeaders(new HttpHeaders()).get('Authorization') != null) == isPresentInHttpHeader
         where: 'the following configurations are used'
index 1da3a55..2f9d264 100644 (file)
@@ -23,28 +23,27 @@ package org.onap.cps.ncmp.api.impl.inventory
 
 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
 import org.onap.cps.spi.utils.CpsValidator
-
 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
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.model.DataNode
 import spock.lang.Shared
 import spock.lang.Specification
 
 class CmHandleQueriesImplSpec extends Specification {
-    def cpsDataPersistenceService = Mock(CpsDataPersistenceService)
+
+    def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
+
+    def trustLevelPerDmiPlugin = [:]
+
+    def trustLevelPerCmHandle = [ 'PNFDemo': TrustLevel.COMPLETE, 'PNFDemo2': TrustLevel.NONE, 'PNFDemo4': TrustLevel.NONE ]
+
     def mockCpsValidator = Mock(CpsValidator)
-    def trustLevelPerCmHandle = [ 'my completed cm handle': TrustLevel.COMPLETE, 'my untrusted cm handle': TrustLevel.NONE ]
 
-    def objectUnderTest = new CmHandleQueriesImpl(cpsDataPersistenceService, trustLevelPerCmHandle, mockCpsValidator)
+    def objectUnderTest = new CmHandleQueriesImpl(mockCpsDataPersistenceService, trustLevelPerDmiPlugin, trustLevelPerCmHandle, mockCpsValidator)
 
     @Shared
     def static sampleDataNodes = [new DataNode()]
@@ -74,13 +73,17 @@ class CmHandleQueriesImplSpec extends Specification {
     }
 
     def 'Query cm handles on trust level'() {
-        given: 'query properties for trustlevel COMPLETE'
+        given: 'query properties for trust level COMPLETE'
             def trustLevelPropertyQueryPairs = ['trustLevel' : TrustLevel.COMPLETE.toString()]
-        when: 'the query is executed'
+        and: 'the dmi cache has been initialised and "knows" about my-dmi-plugin-identifier'
+            trustLevelPerDmiPlugin.put('my-dmi-plugin-identifier', TrustLevel.COMPLETE)
+        and: 'the DataNodes queried for a given cpsPath are returned from the persistence service'
+            mockResponses()
+        when: 'the query is run'
             def result = objectUnderTest.queryCmHandlesByTrustLevel(trustLevelPropertyQueryPairs)
-        then: 'the result only contains the completed cm handle'
+        then: 'the result contain trusted PNFDemo'
             assert result.size() == 1
-            assert result[0] == 'my completed cm handle'
+            assert result[0] == 'PNFDemo'
     }
 
     def 'Query CmHandles using empty public properties query pair.'() {
@@ -99,7 +102,7 @@ class CmHandleQueriesImplSpec extends Specification {
 
     def 'Query CmHandles by a private field\'s value.'() {
         given: 'a data node exists with a certain additional-property'
-            cpsDataPersistenceService.queryDataNodes(_, _, dataNodeWithPrivateField, _) >> [pnfDemo5]
+            mockCpsDataPersistenceService.queryDataNodes(_, _, dataNodeWithPrivateField, _) >> [pnfDemo5]
         when: 'a query on CmHandle private properties is executed using a map'
             def result = objectUnderTest.queryCmHandleAdditionalProperties(['Contact3': 'newemailforstore3@bookstore.com'])
         then: 'one cm handle is returned'
@@ -110,7 +113,7 @@ class CmHandleQueriesImplSpec extends Specification {
         given: 'a cm handle state to query'
             def cmHandleState = CmHandleState.ADVISED
         and: 'the persistence service returns a list of data nodes'
-            cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+            mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                 '//state[@cm-handle-state="ADVISED"]/ancestor::cm-handles', INCLUDE_ALL_DESCENDANTS) >> sampleDataNodes
         when: 'cm handles are fetched by state'
             def result = objectUnderTest.queryCmHandlesByState(cmHandleState)
@@ -122,7 +125,7 @@ class CmHandleQueriesImplSpec extends Specification {
         given: 'a cm handle state to compare'
             def cmHandleState = state
         and: 'the persistence service returns a list of data nodes'
-            cpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+            mockCpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                     NCMP_DMI_REGISTRY_PARENT + '/cm-handles[@id=\'some-cm-handle\']/state',
                     OMIT_DESCENDANTS) >> [new DataNode(leaves: ['cm-handle-state': 'READY'])]
         when: 'cm handles are compared by state'
@@ -139,7 +142,7 @@ class CmHandleQueriesImplSpec extends Specification {
         given: 'a cm handle state to query'
             def cmHandleState = CmHandleState.READY
         and: 'cps data service returns a list of data nodes'
-            cpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+            mockCpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                     NCMP_DMI_REGISTRY_PARENT + '/cm-handles[@id=\'some-cm-handle\']/state',
                     OMIT_DESCENDANTS) >> [new DataNode(leaves: ['cm-handle-state': 'READY'])]
         when: 'cm handles are fetched by state and id'
@@ -152,7 +155,7 @@ class CmHandleQueriesImplSpec extends Specification {
         given: 'a cm handle state to query'
             def cmHandleState = CmHandleState.READY
         and: 'cps data service returns a list of data nodes'
-            cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+            mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                 '//state/datastores/operational[@sync-state="'+'UNSYNCHRONIZED'+'"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> sampleDataNodes
         when: 'cm handles are fetched by the UNSYNCHRONIZED operational sync state'
             def result = objectUnderTest.queryCmHandlesByOperationalSyncState(DataStoreSyncState.UNSYNCHRONIZED)
@@ -165,7 +168,7 @@ class CmHandleQueriesImplSpec extends Specification {
             def cmHandleDataNode = new DataNode(xpath: 'xpath', leaves: ['cm-handle-state': 'LOCKED'])
             def cpsPath = '//cps-path'
         and: 'cps data service returns a valid data node'
-            cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+            mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                 cpsPath + '/ancestor::cm-handles', INCLUDE_ALL_DESCENDANTS)
                 >> Arrays.asList(cmHandleDataNode)
         when: 'get cm handles by cps path is invoked'
@@ -186,15 +189,15 @@ class CmHandleQueriesImplSpec extends Specification {
     }
 
     void mockResponses() {
-        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact\" and @value=\"newemailforstore@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo2, pnfDemo4]
-        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"wont_match\" and @value=\"wont_match\"]/ancestor::cm-handles', _) >> []
-        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"newemailforstore2@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo4]
-        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"\"]/ancestor::cm-handles', _) >> []
-        cpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"READY\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo3]
-        cpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"LOCKED\"]/ancestor::cm-handles', _) >> [pnfDemo2, pnfDemo4]
-        cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo2]
-        cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo4]
-        cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-model-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo2, pnfDemo4]
+        mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact\" and @value=\"newemailforstore@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo2, pnfDemo4]
+        mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"wont_match\" and @value=\"wont_match\"]/ancestor::cm-handles', _) >> []
+        mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"newemailforstore2@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo4]
+        mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"\"]/ancestor::cm-handles', _) >> []
+        mockCpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"READY\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo3]
+        mockCpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"LOCKED\"]/ancestor::cm-handles', _) >> [pnfDemo2, pnfDemo4]
+        mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo2]
+        mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo4]
+        mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-model-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo2, pnfDemo4]
     }
 
     def static createDataNode(dataNodeId) {
@@ -1,6 +1,6 @@
 /*
- *  ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation
+ * ============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.
@@ -9,7 +9,7 @@
  *        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,
+ *  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.
 
 package org.onap.cps.ncmp.api.impl.trustlevel
 
-
 import spock.lang.Specification
 
-class TrustLevelFilterSpec extends Specification {
-
-    def targetTrustLevel = TrustLevel.COMPLETE
-
-    def trustLevelPerCmHandle = [ 'my completed cm handle': TrustLevel.COMPLETE, 'my untrusted cm handle': TrustLevel.NONE ]
+class TrustLevelTest extends Specification {
 
-    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'
+    def 'Get effective trust level between this and other.'() {
+        expect: 'the lower of two is returned'
+            assert effectiveLevel == current.getEffectiveTrustLevel(other)
+        where: 'the following trust level is used'
+            current             | other               || effectiveLevel
+            TrustLevel.COMPLETE | TrustLevel.NONE     || TrustLevel.NONE
+            TrustLevel.NONE     | TrustLevel.COMPLETE || TrustLevel.NONE
+            TrustLevel.COMPLETE | TrustLevel.COMPLETE || TrustLevel.COMPLETE
     }
+
 }
@@ -24,27 +24,27 @@ import org.onap.cps.ncmp.api.impl.client.DmiRestClient
 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
 import spock.lang.Specification
 
-class DMiPluginWatchDogSpec extends Specification {
+class DmiPluginWatchDogSpec extends Specification {
 
-
-    def mockTrustLevelPerDmiPlugin = Mock(Map<String, TrustLevel>)
     def mockDmiRestClient = Mock(DmiRestClient)
-    def objectUnderTest = new DMiPluginWatchDog(mockTrustLevelPerDmiPlugin, mockDmiRestClient)
-
-
-    def 'watch dmi plugin aliveness'() {
-        given: 'the dmi client returns aliveness for #dmi1Status'
-            mockDmiRestClient.getDmiPluginStatus('dmi1') >> dmi1Status
-        and: 'trust level cache returns dmi1'
-            mockTrustLevelPerDmiPlugin.keySet() >> {['dmi1'] as Set}
-        when: 'watch dog started'
-            objectUnderTest.watchDmiPluginAliveness()
-        then: 'trust level cache has been populated with #dmi1TrustLevel for dmi1'
-            1 * mockTrustLevelPerDmiPlugin.put('dmi1', dmi1TrustLevel)
-        where: 'the following parameter are used'
-            scenario                  | dmi1Status              || dmi1TrustLevel
-            'dmi1 is UP'              | DmiPluginStatus.UP      || TrustLevel.COMPLETE
-            'dmi1 is DOWN'            | DmiPluginStatus.DOWN    || TrustLevel.NONE
+    def trustLevelPerDmiPlugin = [:]
+
+    def objectUnderTest = new DmiPluginWatchDog(mockDmiRestClient, trustLevelPerDmiPlugin)
+
+    def 'watch dmi plugin health status for #dmiHealhStatus'() {
+        given: 'the cache has been initialised and "knows" about dmi-1'
+            trustLevelPerDmiPlugin.put('dmi-1',null)
+        and: 'dmi client returns health status #dmiHealhStatus'
+            mockDmiRestClient.getDmiHealthStatus('dmi-1') >> dmiHealhStatus
+        when: 'dmi watch dog method runs'
+            objectUnderTest.watchDmiPluginTrustLevel()
+        then: 'the result is as expected'
+            assert trustLevelPerDmiPlugin.get('dmi-1') == expectedResult
+        where: 'the following health status is used'
+            dmiHealhStatus || expectedResult
+            'UP'           || TrustLevel.COMPLETE
+            'Other'        || TrustLevel.NONE
+            null           || TrustLevel.NONE
     }
 
 }