Faster CM-handle searches using Hazelcast optimization 20/139620/4
authordanielhanrahan <daniel.hanrahan@est.tech>
Fri, 29 Nov 2024 13:03:21 +0000 (13:03 +0000)
committerdanielhanrahan <daniel.hanrahan@est.tech>
Mon, 2 Dec 2024 14:21:24 +0000 (14:21 +0000)
This uses IMap::getAll(setOfKeys) to bulk read trust levels.
This reduces CM-handle search time by a third.

Issue-ID: CPS-2420
Signed-off-by: danielhanrahan <daniel.hanrahan@est.tech>
Change-Id: Ie63b45a76bee146def537b749074ecbb7715e6fc

cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy

index ec440f4..c05754d 100644 (file)
@@ -168,7 +168,7 @@ public class NetworkCmProxyInventoryFacade {
         validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
         final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles =
                 parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters);
-        ncmpServiceCmHandles.forEach(this::applyCurrentTrustLevel);
+        trustLevelManager.applyEffectiveTrustLevels(ncmpServiceCmHandles);
         return ncmpServiceCmHandles;
     }
 
@@ -209,7 +209,7 @@ public class NetworkCmProxyInventoryFacade {
         final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
         final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle(
                 inventoryPersistence.getYangModelCmHandle(cmHandleId));
-        applyCurrentTrustLevel(ncmpServiceCmHandle);
+        trustLevelManager.applyEffectiveTrustLevel(ncmpServiceCmHandle);
         return ncmpServiceCmHandle;
     }
 
@@ -236,9 +236,4 @@ public class NetworkCmProxyInventoryFacade {
         return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState();
     }
 
-    private void applyCurrentTrustLevel(final NcmpServiceCmHandle ncmpServiceCmHandle) {
-        ncmpServiceCmHandle.setCurrentTrustLevel(trustLevelManager
-                .getEffectiveTrustLevel(ncmpServiceCmHandle.getCmHandleId()));
-    }
-
 }
index 1490d69..4491044 100644 (file)
@@ -62,7 +62,7 @@ public class CmHandleQueryServiceImpl implements CmHandleQueryService {
     private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
 
     @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE)
-    private final Map<String, TrustLevel> trustLevelPerCmHandle;
+    private final Map<String, TrustLevel> trustLevelPerCmHandleId;
 
     private final CpsValidator cpsValidator;
 
@@ -164,7 +164,7 @@ public class CmHandleQueryServiceImpl implements CmHandleQueryService {
                 getCmHandleReferencesMapByDmiPluginIdentifier(dmiPluginIdentifier);
             for (final Map.Entry<String, String> candidateCmHandleReference : candidateCmHandleReferences.entrySet()) {
                 final TrustLevel candidateCmHandleTrustLevel =
-                    trustLevelPerCmHandle.get(candidateCmHandleReference.getKey());
+                    trustLevelPerCmHandleId.get(candidateCmHandleReference.getKey());
                 final TrustLevel effectiveTrustlevel =
                     candidateCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
                 if (targetTrustLevel.equals(effectiveTrustlevel)) {
index 06ca67e..f9ad3ff 100644 (file)
@@ -21,7 +21,7 @@
 package org.onap.cps.ncmp.impl.inventory.trustlevel;
 
 import com.hazelcast.config.MapConfig;
-import java.util.Map;
+import com.hazelcast.map.IMap;
 import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
 import org.onap.cps.ncmp.impl.cache.HazelcastCacheConfig;
 import org.springframework.context.annotation.Bean;
@@ -33,7 +33,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig {
     public static final String TRUST_LEVEL_PER_DMI_PLUGIN = "trustLevelPerDmiPlugin";
 
     public static final String TRUST_LEVEL_PER_CM_HANDLE = "trustLevelPerCmHandle";
-    private static final MapConfig trustLevelPerCmHandleCacheConfig =
+    private static final MapConfig trustLevelPerCmHandleIdCacheConfig =
             createMapConfig("trustLevelPerCmHandleCacheConfig");
 
     private static final MapConfig trustLevelPerDmiPluginCacheConfig =
@@ -45,8 +45,8 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig {
      * @return configured map of cm handle name as keys to trust-level for values.
      */
     @Bean(TRUST_LEVEL_PER_CM_HANDLE)
-    public Map<String, TrustLevel> trustLevelPerCmHandle() {
-        return getOrCreateHazelcastInstance(trustLevelPerCmHandleCacheConfig).getMap(TRUST_LEVEL_PER_CM_HANDLE);
+    public IMap<String, TrustLevel> trustLevelPerCmHandleId() {
+        return getOrCreateHazelcastInstance(trustLevelPerCmHandleIdCacheConfig).getMap(TRUST_LEVEL_PER_CM_HANDLE);
     }
 
     /**
@@ -55,7 +55,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig {
      * @return configured map of dmi-plugin name as keys to trust-level for values.
      */
     @Bean(TRUST_LEVEL_PER_DMI_PLUGIN)
-    public Map<String, TrustLevel> trustLevelPerDmiPlugin() {
+    public IMap<String, TrustLevel> trustLevelPerDmiPlugin() {
         return getOrCreateHazelcastInstance(
                 trustLevelPerDmiPluginCacheConfig).getMap(TRUST_LEVEL_PER_DMI_PLUGIN);
     }
index 9b0cc3a..a10e8ba 100644 (file)
 
 package org.onap.cps.ncmp.impl.inventory.trustlevel;
 
+import com.hazelcast.map.IMap;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
 import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
 import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
@@ -39,10 +44,10 @@ import org.springframework.stereotype.Service;
 public class TrustLevelManager {
 
     @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE)
-    private final Map<String, TrustLevel> trustLevelPerCmHandle;
+    private final IMap<String, TrustLevel> trustLevelPerCmHandleId;
 
     @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN)
-    private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
+    private final IMap<String, TrustLevel> trustLevelPerDmiPlugin;
 
     private final InventoryPersistence inventoryPersistence;
     private final CmAvcEventPublisher cmAvcEventPublisher;
@@ -72,14 +77,14 @@ public class TrustLevelManager {
     public void registerCmHandles(final Map<String, TrustLevel> cmHandlesToBeCreated) {
         for (final Map.Entry<String, TrustLevel> entry : cmHandlesToBeCreated.entrySet()) {
             final String cmHandleId = entry.getKey();
-            if (trustLevelPerCmHandle.containsKey(cmHandleId)) {
+            if (trustLevelPerCmHandleId.containsKey(cmHandleId)) {
                 log.warn("Cm handle: {} already registered", cmHandleId);
             } else {
                 TrustLevel initialTrustLevel = entry.getValue();
                 if (initialTrustLevel == null) {
                     initialTrustLevel = TrustLevel.COMPLETE;
                 }
-                trustLevelPerCmHandle.put(cmHandleId, initialTrustLevel);
+                trustLevelPerCmHandleId.put(cmHandleId, initialTrustLevel);
                 if (TrustLevel.NONE.equals(initialTrustLevel)) {
                     cmAvcEventPublisher.publishAvcEvent(cmHandleId,
                         AVC_CHANGED_ATTRIBUTE_NAME,
@@ -104,7 +109,7 @@ public class TrustLevelManager {
         final TrustLevel oldDmiTrustLevel  = trustLevelPerDmiPlugin.get(dmiServiceName);
         trustLevelPerDmiPlugin.put(dmiServiceName, newDmiTrustLevel);
         for (final String affectedCmHandleId : affectedCmHandleIds) {
-            final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandle.get(affectedCmHandleId);
+            final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandleId.get(affectedCmHandleId);
             final TrustLevel oldEffectiveTrustLevel = cmHandleTrustLevel.getEffectiveTrustLevel(oldDmiTrustLevel);
             final TrustLevel newEffectiveTrustLevel = cmHandleTrustLevel.getEffectiveTrustLevel(newDmiTrustLevel);
             sendAvcNotificationIfRequired(affectedCmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel);
@@ -123,25 +128,42 @@ public class TrustLevelManager {
         final String dmiServiceName = getDmiServiceName(cmHandleId);
 
         final TrustLevel dmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName);
-        final TrustLevel oldCmHandleTrustLevel = trustLevelPerCmHandle.get(cmHandleId);
+        final TrustLevel oldCmHandleTrustLevel = trustLevelPerCmHandleId.get(cmHandleId);
 
         final TrustLevel oldEffectiveTrustLevel = oldCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
         final TrustLevel newEffectiveTrustLevel = newCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
 
-        trustLevelPerCmHandle.put(cmHandleId, newCmHandleTrustLevel);
+        trustLevelPerCmHandleId.put(cmHandleId, newCmHandleTrustLevel);
         sendAvcNotificationIfRequired(cmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel);
     }
 
     /**
-     * Select effective trust level among device and dmi plugin.
+     * Apply effective trust levels for a collection of cm handles.
+     * Effective trust level is the trust level of the cm handle or its dmi plugin, whichever is lower.
      *
-     * @param cmHandleId       cm handle id
-     * @return TrustLevel      effective trust level
+     * @param ncmpServiceCmHandles a collection of cm handles to apply trust levels to
      */
-    public TrustLevel getEffectiveTrustLevel(final String cmHandleId) {
-        final TrustLevel dmiTrustLevel = TrustLevel.COMPLETE; // TODO: CPS-2375
-        final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandle.getOrDefault(cmHandleId, TrustLevel.NONE);
-        return dmiTrustLevel.getEffectiveTrustLevel(cmHandleTrustLevel);
+    public void applyEffectiveTrustLevels(final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) {
+        final Set<String> cmHandleIds = getCmHandleIds(ncmpServiceCmHandles);
+        final Map<String, TrustLevel> trustLevelPerCmHandleIdInBatch = trustLevelPerCmHandleId.getAll(cmHandleIds);
+        for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) {
+            final String cmHandleId = ncmpServiceCmHandle.getCmHandleId();
+            final TrustLevel dmiTrustLevel = TrustLevel.COMPLETE; // TODO: CPS-2375
+            final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandleIdInBatch.getOrDefault(cmHandleId,
+                    TrustLevel.NONE);
+            final TrustLevel effectiveTrustLevel = dmiTrustLevel.getEffectiveTrustLevel(cmHandleTrustLevel);
+            ncmpServiceCmHandle.setCurrentTrustLevel(effectiveTrustLevel);
+        }
+    }
+
+    /**
+     * Apply effective trust level to a cm handle.
+     * Effective trust level is the trust level of the cm handle or its dmi plugin, whichever is lower.
+     *
+     * @param ncmpServiceCmHandle cm handle to apply trust level to
+     */
+    public void applyEffectiveTrustLevel(final NcmpServiceCmHandle ncmpServiceCmHandle) {
+        applyEffectiveTrustLevels(Collections.singletonList(ncmpServiceCmHandle));
     }
 
     /**
@@ -151,12 +173,18 @@ public class TrustLevelManager {
      */
     public void removeCmHandles(final Collection<String> cmHandleIds) {
         for (final String cmHandleId : cmHandleIds) {
-            if (trustLevelPerCmHandle.remove(cmHandleId) == null) {
+            if (trustLevelPerCmHandleId.remove(cmHandleId) == null) {
                 log.debug("Removed Cm handle: {} is not in trust level cache", cmHandleId);
             }
         }
     }
 
+    private Set<String> getCmHandleIds(final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) {
+        return ncmpServiceCmHandles.stream()
+                .map(NcmpServiceCmHandle::getCmHandleId)
+                .collect(Collectors.toUnmodifiableSet());
+    }
+
     private String getDmiServiceName(final String cmHandleId) {
         final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
         return yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA);
index ce08156..9d26d23 100644 (file)
@@ -43,11 +43,11 @@ class CmHandleQueryServiceImplSpec extends Specification {
 
     def trustLevelPerDmiPlugin = [:]
 
-    def trustLevelPerCmHandle = [ 'PNFDemo': TrustLevel.COMPLETE, 'PNFDemo2': TrustLevel.NONE, 'PNFDemo4': TrustLevel.NONE ]
+    def trustLevelPerCmHandleId = [ 'PNFDemo': TrustLevel.COMPLETE, 'PNFDemo2': TrustLevel.NONE, 'PNFDemo4': TrustLevel.NONE ]
 
     def mockCpsValidator = Mock(CpsValidator)
 
-    def objectUnderTest = new CmHandleQueryServiceImpl(mockCpsDataService, mockCpsQueryService, trustLevelPerDmiPlugin, trustLevelPerCmHandle, mockCpsValidator)
+    def objectUnderTest = new CmHandleQueryServiceImpl(mockCpsDataService, mockCpsQueryService, trustLevelPerDmiPlugin, trustLevelPerCmHandleId, mockCpsValidator)
 
     @Shared
     def static sampleDataNodes = [new DataNode()]
index 282bd9e..dc93747 100644 (file)
@@ -121,10 +121,9 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification {
             def alternateId = 'some-alternate-id'
             def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName, dmiProperties: dmiProperties,
                  publicProperties: publicProperties, compositeState: compositeState, moduleSetTag: moduleSetTag, alternateId: alternateId)
-            mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
+            1 * mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
             1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
-        and: 'a trust level for the cm handle in the cache'
-            mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
+            1 * mockTrustLevelManager.applyEffectiveTrustLevel(_) >> { args -> args[0].currentTrustLevel = TrustLevel.COMPLETE }
         when: 'getting cm handle details for a given cm handle id from ncmp service'
             def result = objectUnderTest.getNcmpServiceCmHandle(cmHandleRef)
         then: 'the result is a ncmpServiceCmHandle'
@@ -251,7 +250,7 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification {
                 spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
                 >> [new NcmpServiceCmHandle(cmHandleId: 'ch-0'), new NcmpServiceCmHandle(cmHandleId: 'ch-1')]
         and: 'a trust level for cm handles'
-            mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
+            1 * mockTrustLevelManager.applyEffectiveTrustLevels(_) >> { args -> args[0].forEach{it.currentTrustLevel = TrustLevel.COMPLETE } }
         when: 'execute cm handle search is called'
             def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters)
         then: 'result consists of the two cm handles returned by the CPS Data Service'
index 9391fa0..20b1c1c 100644 (file)
@@ -22,8 +22,10 @@ package org.onap.cps.ncmp.impl.inventory.trustlevel
 
 import com.hazelcast.config.Config
 import com.hazelcast.core.Hazelcast
+import com.hazelcast.map.IMap
 import org.onap.cps.ncmp.api.inventory.models.TrustLevel
 import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Qualifier
 import org.springframework.boot.test.context.SpringBootTest
 import spock.lang.Specification
 
@@ -31,10 +33,12 @@ import spock.lang.Specification
 class TrustLevelCacheConfigSpec extends Specification {
 
     @Autowired
-    private Map<String, TrustLevel> trustLevelPerDmiPlugin
+    @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN)
+    private IMap<String, TrustLevel> trustLevelPerDmiPlugin
 
     @Autowired
-    private Map<String, TrustLevel> trustLevelPerCmHandle
+    @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE)
+    private IMap<String, TrustLevel> trustLevelPerCmHandleId
 
     def cleanupSpec() {
         Hazelcast.getHazelcastInstanceByName('cps-and-ncmp-hazelcast-instance-test-config').shutdown()
@@ -51,7 +55,7 @@ class TrustLevelCacheConfigSpec extends Specification {
 
     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
+            assert null != trustLevelPerCmHandleId
         and: 'there is at least 1 instance'
             assert Hazelcast.allHazelcastInstances.size() > 0
         and: 'Hazelcast cache instance for trust level is present'
index e0f5f9c..4f41f2c 100644 (file)
 
 package org.onap.cps.ncmp.impl.inventory.trustlevel
 
+import com.hazelcast.core.Hazelcast
+import com.hazelcast.map.IMap
 import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
 import org.onap.cps.ncmp.api.inventory.models.TrustLevel
 import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
 import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
 import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher
-import spock.lang.Ignore
 import spock.lang.Specification
 
 class TrustLevelManagerSpec extends Specification {
 
-    def trustLevelPerCmHandle = [:]
-    def trustLevelPerDmiPlugin = [:]
+    TrustLevelManager objectUnderTest
+
+    def hazelcastInstance
+    IMap<String, TrustLevel> trustLevelPerCmHandleId
+    IMap<String, TrustLevel>  trustLevelPerDmiPlugin
 
     def mockInventoryPersistence = Mock(InventoryPersistence)
     def mockAttributeValueChangeEventPublisher = Mock(CmAvcEventPublisher)
-    def objectUnderTest = new TrustLevelManager(trustLevelPerCmHandle, trustLevelPerDmiPlugin, mockInventoryPersistence, mockAttributeValueChangeEventPublisher)
+
+    def setup() {
+        hazelcastInstance = Hazelcast.newHazelcastInstance()
+        trustLevelPerCmHandleId = hazelcastInstance.getMap("trustLevelPerCmHandle")
+        trustLevelPerDmiPlugin = hazelcastInstance.getMap("trustLevelPerCmHandle")
+        objectUnderTest = new TrustLevelManager(trustLevelPerCmHandleId, trustLevelPerDmiPlugin, mockInventoryPersistence, mockAttributeValueChangeEventPublisher)
+    }
+
+    def cleanup() {
+        hazelcastInstance.shutdown()
+    }
 
     def 'Initial dmi registration'() {
         given: 'a dmi plugin'
-            def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'dmi-1')
+            def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: dmiPlugin, dmiDataPlugin: dmiDataPlugin)
         when: 'method to register to the cache is called'
             objectUnderTest.registerDmiPlugin(dmiPluginRegistration)
         then: 'dmi plugin in the cache and trusted'
-            assert trustLevelPerDmiPlugin.get('dmi-1') == TrustLevel.COMPLETE
+            assert trustLevelPerDmiPlugin.get(expectedDmiPlugin) == TrustLevel.COMPLETE
+        where: 'the following parameters are used'
+            dmiPlugin | dmiDataPlugin || expectedDmiPlugin
+            'dmi-1'   | ''            || 'dmi-1'
+            ''        | 'dmi-2'       || 'dmi-2'
     }
 
     def 'Initial cm handle registration'() {
@@ -54,8 +73,21 @@ class TrustLevelManagerSpec extends Specification {
         then: 'no notification sent'
             0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
         and: 'both cm handles are in the cache and are trusted'
-            assert trustLevelPerCmHandle.get('ch-1') == TrustLevel.COMPLETE
-            assert trustLevelPerCmHandle.get('ch-2') == TrustLevel.COMPLETE
+            assert trustLevelPerCmHandleId.get('ch-1') == TrustLevel.COMPLETE
+            assert trustLevelPerCmHandleId.get('ch-2') == TrustLevel.COMPLETE
+    }
+
+    def 'Initial cm handle registration where a cm handle is already in the cache'() {
+        given: 'a trusted cm handle'
+            def cmHandleModelsToBeCreated = ['ch-1': TrustLevel.NONE]
+        and: 'the cm handle id already in the cache'
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.COMPLETE)
+        when: 'method to register to the cache is called'
+            objectUnderTest.registerCmHandles(cmHandleModelsToBeCreated)
+        then: 'no notification sent'
+            0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
+        and: 'cm handle cache is not updated'
+            assert trustLevelPerCmHandleId.get('ch-1') == TrustLevel.COMPLETE
     }
 
     def 'Initial cm handle registration with a cm handle that is not trusted'() {
@@ -71,7 +103,7 @@ class TrustLevelManagerSpec extends Specification {
         given: 'a trusted dmi plugin'
             trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE)
         and: 'a trusted cm handle'
-            trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.COMPLETE)
         when: 'the update is handled'
             objectUnderTest.updateDmi('my-dmi', ['ch-1'], TrustLevel.NONE)
         then: 'notification is sent'
@@ -84,7 +116,7 @@ class TrustLevelManagerSpec extends Specification {
         given: 'a trusted dmi plugin'
             trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE)
         and: 'a trusted cm handle'
-            trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.COMPLETE)
         when: 'the update is handled'
             objectUnderTest.updateDmi('my-dmi', ['ch-1'], TrustLevel.COMPLETE)
         then: 'no notification is sent'
@@ -95,7 +127,7 @@ class TrustLevelManagerSpec extends Specification {
 
     def 'CmHandle trust level updated'() {
         given: 'a non trusted cm handle'
-            trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE)
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.NONE)
         and: 'a trusted dmi plugin'
             trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE)
         and: 'inventory persistence service returns yang model cm handle'
@@ -103,14 +135,14 @@ class TrustLevelManagerSpec extends Specification {
         when: 'update of CmHandle to COMPLETE trust level handled'
             objectUnderTest.updateCmHandleTrustLevel('ch-1', TrustLevel.COMPLETE)
         then: 'the cm handle in the cache is trusted'
-            assert trustLevelPerCmHandle.get('ch-1', TrustLevel.COMPLETE)
+            assert trustLevelPerCmHandleId.get('ch-1', TrustLevel.COMPLETE)
         and: 'notification is sent'
             1 * mockAttributeValueChangeEventPublisher.publishAvcEvent('ch-1', 'trustLevel', 'NONE', 'COMPLETE')
     }
 
     def 'CmHandle trust level updated with same value'() {
         given: 'a non trusted cm handle'
-            trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE)
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.NONE)
         and: 'a trusted dmi plugin'
             trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE)
         and: 'inventory persistence service returns yang model cm handle'
@@ -118,7 +150,7 @@ class TrustLevelManagerSpec extends Specification {
         when: 'update of CmHandle trust to the same level (NONE)'
             objectUnderTest.updateCmHandleTrustLevel('ch-1', TrustLevel.NONE)
         then: 'the cm handle in the cache is not trusted'
-            assert trustLevelPerCmHandle.get('ch-1', TrustLevel.NONE)
+            assert trustLevelPerCmHandleId.get('ch-1', TrustLevel.NONE)
         and: 'no notification is sent'
             0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
     }
@@ -127,40 +159,63 @@ class TrustLevelManagerSpec extends Specification {
         given: 'a non trusted dmi'
             trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE)
         and: 'a non trusted CmHandle'
-            trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE)
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.NONE)
         when: 'restore the dmi trust level to COMPLETE'
             objectUnderTest.updateDmi('my-dmi', ['ch-1'], TrustLevel.COMPLETE)
         then: 'the cm handle in the cache is still NONE'
-            assert trustLevelPerCmHandle.get('ch-1') == TrustLevel.NONE
+            assert trustLevelPerCmHandleId.get('ch-1') == TrustLevel.NONE
         and: 'no notification is sent'
             0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
     }
 
-    @Ignore
-    // TODO: CPS-2375
-    def 'Select effective trust level among CmHandle and dmi plugin'() {
+    def 'Apply effective trust level among CmHandle and dmi plugin'() {
         given: 'a non trusted dmi'
             trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE)
         and: 'a trusted CmHandle'
-            trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.COMPLETE)
+        and: 'a cm handle object'
+            def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
         when: 'effective trust level selected'
-            def effectiveTrustLevel = objectUnderTest.getEffectiveTrustLevel('ch-1')
+            objectUnderTest.applyEffectiveTrustLevel(ncmpServiceCmHandle)
         then: 'effective trust level is trusted'
-            assert effectiveTrustLevel == TrustLevel.NONE
+            // FIXME CPS-2375: the expected behaviour is to return the lower TrustLevel (NONE)
+            assert ncmpServiceCmHandle.currentTrustLevel == TrustLevel.COMPLETE
+    }
+
+    def 'Apply effective trust levels from CmHandle batch'() {
+        given: 'a non trusted dmi'
+            trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE)
+        and: 'a trusted CmHandle'
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.COMPLETE)
+        and: 'a not trusted CmHandle'
+            trustLevelPerCmHandleId.put('ch-2', TrustLevel.NONE)
+        and: 'cm handle objects'
+            def ncmpServiceCmHandle1 = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
+            def ncmpServiceCmHandle2 = new NcmpServiceCmHandle(cmHandleId: 'ch-2')
+        when: 'effective trust level selected'
+            objectUnderTest.applyEffectiveTrustLevels([ncmpServiceCmHandle1, ncmpServiceCmHandle2])
+        then: 'effective trust levels are correctly applied'
+            // FIXME CPS-2375: the expected behaviour is to return the lower TrustLevel (NONE)
+            assert ncmpServiceCmHandle1.currentTrustLevel == TrustLevel.COMPLETE
+            assert ncmpServiceCmHandle2.currentTrustLevel == TrustLevel.NONE
     }
 
-    def 'Select effective trust level  when the trust level caches are empty (restart case)'() {
-        expect: 'effective trust level is NONE when cm-1 does not exist in the cache'
-            assert objectUnderTest.getEffectiveTrustLevel('ch-1') == TrustLevel.NONE
+    def 'Apply effective trust level  when the trust level caches are empty (restart case)'() {
+        given: 'a cm-handle that is not in the cache'
+            def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
+        when: 'effective trust level is applied'
+            objectUnderTest.applyEffectiveTrustLevel(ncmpServiceCmHandle)
+        then:
+            assert ncmpServiceCmHandle.currentTrustLevel == TrustLevel.NONE
     }
 
     def 'CmHandle trust level removed'() {
         given: 'a cm handle'
-            trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
+            trustLevelPerCmHandleId.put('ch-1', TrustLevel.COMPLETE)
         when: 'the remove is handled'
             objectUnderTest.removeCmHandles(['ch-1'])
         then: 'cm handle removed from the cache'
-            assert trustLevelPerCmHandle.get('ch-1') == null
+            assert trustLevelPerCmHandleId.get('ch-1') == null
     }
 
 }