Merge "CmHandleState transition using state handler"
authorToine Siebelink <toine.siebelink@est.tech>
Fri, 12 Aug 2022 13:41:17 +0000 (13:41 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 12 Aug 2022 13:41:17 +0000 (13:41 +0000)
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/event/lcm/LcmEventsCreatorHelper.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateUtils.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.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/event/lcm/LcmEventsCreatorSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy

index 8462d68..0fdecde 100755 (executable)
@@ -271,17 +271,12 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>();
         try {
             cmHandleRegistrationResponses = dmiPluginRegistration.getCreatedCmHandles().stream()
-                .map(cmHandle -> {
-                    setCompositeStateToAdvised(cmHandle);
-                    return YangModelCmHandle.toYangModelCmHandle(
+                .map(cmHandle ->
+                    YangModelCmHandle.toYangModelCmHandle(
                         dmiPluginRegistration.getDmiPlugin(),
                         dmiPluginRegistration.getDmiDataPlugin(),
                         dmiPluginRegistration.getDmiModelPlugin(),
-                        cmHandle);
-                    }
-                )
-                .map(this::registerNewCmHandle)
-                .collect(Collectors.toList());
+                        cmHandle)).map(this::registerNewCmHandle).collect(Collectors.toList());
         } catch (final DataValidationException dataValidationException) {
             cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createFailureResponse(dmiPluginRegistration
                             .getCreatedCmHandles().stream()
@@ -291,13 +286,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         return cmHandleRegistrationResponses;
     }
 
-    private void setCompositeStateToAdvised(final NcmpServiceCmHandle ncmpServiceCmHandle) {
-        final CompositeState compositeState = new CompositeState();
-        compositeState.setCmHandleState(CmHandleState.ADVISED);
-        compositeState.setLastUpdateTimeNow();
-        ncmpServiceCmHandle.setCompositeState(compositeState);
-    }
-
     protected List<CmHandleRegistrationResponse> parseAndRemoveCmHandlesInDmiRegistration(
             final List<String> tobeRemovedCmHandles) {
         final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
@@ -339,7 +327,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private CmHandleRegistrationResponse registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) {
         try {
-            inventoryPersistence.saveCmHandle(yangModelCmHandle);
+            lcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle, CmHandleState.ADVISED);
             return CmHandleRegistrationResponse.createSuccessResponse(yangModelCmHandle.getId());
         } catch (final AlreadyDefinedException alreadyDefinedException) {
             return CmHandleRegistrationResponse.createFailureResponse(
index 1f2cf97..40f70b9 100644 (file)
@@ -99,32 +99,32 @@ public class LcmEventsCreatorHelper {
             final NcmpServiceCmHandle targetNcmpServiceCmHandle,
             final NcmpServiceCmHandle existingNcmpServiceCmHandle) {
 
-        final boolean isDataSyncFlagEnabledChanged =
-                isDataSyncEnabledFlagChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle);
-        final boolean isCmHandleStateChanged =
-                isCmHandleStateChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle);
-        final boolean isPublicCmHandlePropertiesEqual =
-                isPublicCmHandlePropertiesEqual(targetNcmpServiceCmHandle.getPublicProperties(),
+        final boolean hasDataSyncFlagEnabledChanged =
+                hasDataSyncEnabledFlagChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle);
+        final boolean hasCmHandleStateChanged =
+                hasCmHandleStateChanged(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle);
+        final boolean arePublicCmHandlePropertiesEqual =
+                arePublicCmHandlePropertiesEqual(targetNcmpServiceCmHandle.getPublicProperties(),
                         existingNcmpServiceCmHandle.getPublicProperties());
 
         final LcmEventsCreator.CmHandleValuesHolder cmHandleValuesHolder = new LcmEventsCreator.CmHandleValuesHolder();
 
-        if (isDataSyncFlagEnabledChanged || isCmHandleStateChanged || (!isPublicCmHandlePropertiesEqual)) {
+        if (hasDataSyncFlagEnabledChanged || hasCmHandleStateChanged || (!arePublicCmHandlePropertiesEqual)) {
             cmHandleValuesHolder.setOldValues(new Values());
             cmHandleValuesHolder.setNewValues(new Values());
         } else {
             return cmHandleValuesHolder;
         }
 
-        if (isDataSyncFlagEnabledChanged) {
+        if (hasDataSyncFlagEnabledChanged) {
             setDataSyncEnabledFlag(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, cmHandleValuesHolder);
         }
 
-        if (isCmHandleStateChanged) {
+        if (hasCmHandleStateChanged) {
             setCmHandleStateChange(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle, cmHandleValuesHolder);
         }
 
-        if (!isPublicCmHandlePropertiesEqual) {
+        if (!arePublicCmHandlePropertiesEqual) {
             setPublicCmHandlePropertiesChange(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle,
                     cmHandleValuesHolder);
         }
@@ -174,21 +174,29 @@ public class LcmEventsCreatorHelper {
         return ncmpServiceCmHandle.getCompositeState().getDataSyncEnabled();
     }
 
-    private static boolean isDataSyncEnabledFlagChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle,
+    private static boolean hasDataSyncEnabledFlagChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle,
             final NcmpServiceCmHandle existingNcmpServiceCmHandle) {
 
-        return !targetNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled()
-                .equals(existingNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled());
+        final Boolean targetDataSyncFlag = targetNcmpServiceCmHandle.getCompositeState() == null
+                                          ? null : targetNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled();
+        final Boolean existingDataSyncFlag = existingNcmpServiceCmHandle.getCompositeState() == null
+                                          ? null : existingNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled();
+
+        if (targetDataSyncFlag == null) {
+            return existingDataSyncFlag != null;
+        }
+
+        return !targetDataSyncFlag.equals(existingDataSyncFlag);
     }
 
-    private static boolean isCmHandleStateChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle,
+    private static boolean hasCmHandleStateChanged(final NcmpServiceCmHandle targetNcmpServiceCmHandle,
             final NcmpServiceCmHandle existingNcmpServiceCmHandle) {
 
         return targetNcmpServiceCmHandle.getCompositeState().getCmHandleState()
                        != existingNcmpServiceCmHandle.getCompositeState().getCmHandleState();
     }
 
-    private static boolean isPublicCmHandlePropertiesEqual(final Map<String, String> targetCmHandleProperties,
+    private static boolean arePublicCmHandlePropertiesEqual(final Map<String, String> targetCmHandleProperties,
             final Map<String, String> existingCmHandleProperties) {
         if (targetCmHandleProperties.size() != existingCmHandleProperties.size()) {
             return false;
index 54ca68a..6fabc93 100644 (file)
@@ -52,6 +52,7 @@ public class CompositeStateUtils {
     public static Consumer<CompositeState> setCompositeStateToReadyWithInitialDataStoreSyncState() {
         return compositeState -> {
             compositeState.setDataSyncEnabled(false);
+            compositeState.setLastUpdateTimeNow();
             compositeState.setCmHandleState(CmHandleState.READY);
             final CompositeState.Operational operational =
                     getInitialDataStoreSyncState(compositeState.getDataSyncEnabled());
@@ -70,6 +71,7 @@ public class CompositeStateUtils {
     public static void setDataSyncEnabledFlagWithDataSyncState(final boolean dataSyncEnabled,
                                                                final CompositeState compositeState) {
         compositeState.setDataSyncEnabled(dataSyncEnabled);
+        compositeState.setLastUpdateTimeNow();
         final CompositeState.Operational operational = getInitialDataStoreSyncState(dataSyncEnabled);
         final CompositeState.DataStores dataStores =
             CompositeState.DataStores.builder().operationalDataStore(operational).build();
index 37bd1ed..7c2a4fc 100644 (file)
@@ -23,13 +23,12 @@ package org.onap.cps.ncmp.api.inventory.sync;
 
 import java.util.List;
 import java.util.concurrent.ConcurrentMap;
-import java.util.function.Consumer;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.ncmp.api.inventory.CmHandleState;
 import org.onap.cps.ncmp.api.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState;
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.inventory.LockReasonCategory;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -48,6 +47,8 @@ public class ModuleSyncWatchdog {
 
     private final ConcurrentMap<String, Boolean> moduleSyncSemaphoreMap;
 
+    private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler;
+
     /**
      * Execute Cm Handle poll which changes the cm handle state from 'ADVISED' to 'READY'.
      */
@@ -61,14 +62,13 @@ public class ModuleSyncWatchdog {
                 try {
                     moduleSyncService.deleteSchemaSetIfExists(advisedCmHandle);
                     moduleSyncService.syncAndCreateSchemaSetAndAnchor(advisedCmHandle);
-                    setCompositeStateToReadyWithInitialDataStoreSyncState().accept(compositeState);
+                    lcmEventsCmHandleStateHandler.updateCmHandleState(advisedCmHandle, CmHandleState.READY);
                     updateModuleSyncSemaphoreMap(cmHandleId);
                 } catch (final Exception e) {
-                    setCompositeStateToLocked().accept(compositeState);
                     syncUtils.updateLockReasonDetailsAndAttempts(compositeState,
                             LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, e.getMessage());
+                    setCmHandleStateLocked(advisedCmHandle, compositeState.getLockReason());
                 }
-                inventoryPersistence.saveCmHandleState(cmHandleId, compositeState);
                 log.debug("{} is now in {} state", cmHandleId, compositeState.getCmHandleState().name());
             } else {
                 log.debug("{} already processed by another instance", cmHandleId);
@@ -87,44 +87,16 @@ public class ModuleSyncWatchdog {
             final CompositeState compositeState = lockedCmHandle.getCompositeState();
             final boolean isReadyForRetry = syncUtils.isReadyForRetry(compositeState);
             if (isReadyForRetry) {
-                setCompositeStateToAdvisedAndRetainOldLockReasonDetails(compositeState);
-                log.debug("Locked cm handle {} is being re-synced", lockedCmHandle.getId());
-                inventoryPersistence.saveCmHandleState(lockedCmHandle.getId(), compositeState);
+                log.debug("Reset cm handle {} state to ADVISED to re-attempt module-sync", lockedCmHandle.getId());
+                lcmEventsCmHandleStateHandler.updateCmHandleState(lockedCmHandle, CmHandleState.ADVISED);
             }
         }
     }
 
-    private Consumer<CompositeState> setCompositeStateToLocked() {
-        return compositeState -> {
-            compositeState.setCmHandleState(CmHandleState.LOCKED);
-            compositeState.setLastUpdateTimeNow();
-        };
-    }
-
-    private Consumer<CompositeState> setCompositeStateToReadyWithInitialDataStoreSyncState() {
-        return compositeState -> {
-            compositeState.setDataSyncEnabled(false);
-            compositeState.setCmHandleState(CmHandleState.READY);
-            final CompositeState.Operational operational = getDataStoreSyncState();
-            final CompositeState.DataStores dataStores = CompositeState.DataStores.builder()
-                    .operationalDataStore(operational)
-                    .build();
-            compositeState.setDataStores(dataStores);
-        };
-    }
-
-    private void setCompositeStateToAdvisedAndRetainOldLockReasonDetails(final CompositeState compositeState) {
-        compositeState.setCmHandleState(CmHandleState.ADVISED);
-        compositeState.setLastUpdateTimeNow();
-        final String oldLockReasonDetails = compositeState.getLockReason().getDetails();
-        final CompositeState.LockReason lockReason = CompositeState.LockReason.builder()
-                .details(oldLockReasonDetails).build();
-        compositeState.setLockReason(lockReason);
-    }
-
-    private CompositeState.Operational getDataStoreSyncState() {
-        final DataStoreSyncState dataStoreSyncState = DataStoreSyncState.NONE_REQUESTED;
-        return CompositeState.Operational.builder().dataStoreSyncState(dataStoreSyncState).build();
+    private void setCmHandleStateLocked(final YangModelCmHandle advisedCmHandle,
+            final CompositeState.LockReason lockReason) {
+        advisedCmHandle.getCompositeState().setLockReason(lockReason);
+        lcmEventsCmHandleStateHandler.updateCmHandleState(advisedCmHandle, CmHandleState.LOCKED);
     }
 
     private void updateModuleSyncSemaphoreMap(final String cmHandleId) {
index 2aa08b8..8d8b3b4 100644 (file)
@@ -156,15 +156,15 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
                 assert it.status == Status.SUCCESS
                 assert it.cmHandle == 'cmhandle'
             }
-        and: 'save cmhandle is invoked once with the expected parameters'
-                1 * mockInventoryPersistence.saveCmHandle(_) >> {
-                    args -> {
+        and: 'state handler is invoked with the expected parameters'
+            1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, _) >> {
+                args -> {
                         def result = (args[0] as YangModelCmHandle)
                         assert result.id == 'cmhandle'
                         assert result.dmiServiceName == 'my-server'
-                        assert result.compositeState.cmHandleState == CmHandleState.ADVISED
+                        assert CmHandleState.ADVISED == (args[1] as CmHandleState)
                     }
-                }
+            }
         where:
             scenario                          | dmiProperties            | publicProperties               || expectedDmiProperties                      | expectedPublicProperties
             'with dmi & public properties'    | ['dmi-key': 'dmi-value'] | ['public-key': 'public-value'] || '[{"name":"dmi-key","value":"dmi-value"}]' | '[{"name":"public-key","value":"public-value"}]'
@@ -181,7 +181,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
                                    new NcmpServiceCmHandle(cmHandleId: 'cmhandle2'),
                                    new NcmpServiceCmHandle(cmHandleId: 'cmhandle3')])
         and: 'cm-handle creation is successful for 1st and 3rd; failed for 2nd'
-            mockInventoryPersistence.saveCmHandle(_) >> {} >> { throw new RuntimeException("Failed") } >> {}
+            mockLcmEventsCmHandleStateHandler.updateCmHandleState(*_) >> {} >> { throw new RuntimeException("Failed") } >> {}
         when: 'registration is updated to create cm-handles'
             def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
         then: 'a response is received for all cm-handles'
@@ -209,7 +209,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
             dmiPluginRegistration.createdCmHandles = [new NcmpServiceCmHandle(cmHandleId: cmHandleId)]
         and: 'cm-handler registration fails: #scenario'
-            mockInventoryPersistence.saveCmHandle(_) >> { throw exception }
+            mockLcmEventsCmHandleStateHandler.updateCmHandleState(*_) >> { throw exception }
         when: 'registration is updated'
             def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
         then: 'a failure response is received'
index a372def..a114b61 100644 (file)
@@ -280,12 +280,12 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
         when: 'parse and create cm handle in dmi registration then sync module'
             objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(mockDmiPluginRegistration)
         then: 'system persists the cm handle state'
-            1 * mockInventoryPersistence.saveCmHandle(_) >> {
+            1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, _) >> {
                 args -> {
-                    def result = (args[0] as YangModelCmHandle)
-                    assert result.id == 'test-cm-handle-id'
-                    assert result.compositeState.cmHandleState == CmHandleState.ADVISED
-                }
+                        def result = (args[0] as YangModelCmHandle)
+                        assert result.id == 'test-cm-handle-id'
+                        assert CmHandleState.ADVISED == (args[1] as CmHandleState)
+                    }
             }
     }
 
index ccf956f..18041fa 100644 (file)
@@ -103,4 +103,50 @@ class LcmEventsCreatorSpec extends Specification {
             assert result.event.oldValues == null
             assert result.event.newValues == null
     }
+
+    def 'Map the LcmEvent for datasync flag transition from #operation'() {
+        given: 'NCMP cm handle details with current and old details'
+            def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: existingDataSyncEnableFlag, cmHandleState: ADVISED))
+            def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: targetDataSyncEnableFlag, cmHandleState: READY))
+        when: 'the event is populated'
+            def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle)
+        then: 'event header is mapped correctly'
+            assert result.eventSource == 'org.onap.ncmp'
+            assert result.eventCorrelationId == cmHandleId
+            assert result.eventType == LcmEventType.UPDATE.eventType
+        and: 'event payload is mapped correctly with correct cmhandle id'
+            assert result.event.cmHandleId == cmHandleId
+        and: 'it should have correct old values'
+            assert result.event.oldValues.cmHandleState == Values.CmHandleState.ADVISED
+            assert result.event.oldValues.dataSyncEnabled == existingDataSyncEnableFlag
+        and: 'the correct new values'
+            assert result.event.newValues.cmHandleState == Values.CmHandleState.READY
+            assert result.event.newValues.dataSyncEnabled == targetDataSyncEnableFlag
+        where: 'following parameters are provided'
+            operation       | existingDataSyncEnableFlag | targetDataSyncEnableFlag
+            'false to true' | false                      | true
+            'false to null' | false                      | null
+            'true to false' | true                       | false
+            'true to null'  | true                       | null
+            'null to true'  | null                       | true
+            'null to false' | null                       | false
+
+    }
+
+    def 'Map the LcmEvent for datasync flag for same transition from #operation'() {
+        given: 'NCMP cm handle details with current and old details'
+            def existingNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: existingDataSyncEnableFlag, cmHandleState: ADVISED))
+            def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: targetDataSyncEnableFlag, cmHandleState: READY))
+        when: 'the event is populated'
+            def result = objectUnderTest.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle)
+        then: 'the data sync flag is not present in the event'
+            assert result.event.oldValues.dataSyncEnabled == null
+            assert result.event.newValues.dataSyncEnabled == null
+        where: 'following parameters are provided'
+            operation        | existingDataSyncEnableFlag | targetDataSyncEnableFlag
+            'false to false' | false                      | false
+            'true to true'   | true                       | true
+            'null to null'   | null                       | null
+
+    }
 }
\ No newline at end of file
index 41f2160..863977a 100644 (file)
@@ -21,6 +21,8 @@
 
 package org.onap.cps.ncmp.api.inventory.sync
 
+import org.mockito.Mock
+import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.ncmp.api.inventory.CompositeState
@@ -43,9 +45,11 @@ class ModuleSyncWatchdogSpec extends Specification {
 
     def stubbedMap = Stub(ConcurrentMap)
 
+    def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
+
     def cmHandleState = CmHandleState.ADVISED
 
-    def objectUnderTest = new ModuleSyncWatchdog(mockInventoryPersistence, mockSyncUtils, mockModuleSyncService, stubbedMap as ConcurrentHashMap)
+    def objectUnderTest = new ModuleSyncWatchdog(mockInventoryPersistence, mockSyncUtils, mockModuleSyncService, stubbedMap as ConcurrentHashMap, mockLcmEventsCmHandleStateHandler)
 
     def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles'() {
         given: 'cm handles in an advised state and a data sync state'
@@ -63,22 +67,14 @@ class ModuleSyncWatchdogSpec extends Specification {
             1 * mockModuleSyncService.deleteSchemaSetIfExists(yangModelCmHandle1)
         and: 'module sync service syncs the first cm handle and creates a schema set'
             1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle1)
-        then: 'the composite state cm handle state is now READY'
-            assert compositeState1.getCmHandleState() == CmHandleState.READY
-        and: 'the data sync enabled flag is set correctly'
-            compositeState1.getDataSyncEnabled() == false
-        and: 'the data store sync state returns the expected state'
-            compositeState1.getDataStores().operationalDataStore.dataStoreSyncState == DataStoreSyncState.NONE_REQUESTED
-        and: 'the first cm handle state is updated'
-            1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle', compositeState1)
-        then: 'the inventory persistence cm handle returns a composite state for the second cm handle'
+        then: 'the state handler is called for the first cm handle'
+            1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle1, CmHandleState.READY)
+        and: 'the inventory persistence cm handle returns a composite state for the second cm handle'
             mockInventoryPersistence.getCmHandleState('some-cm-handle-2') >> compositeState2
         and: 'module sync service syncs the second cm handle and creates a schema set'
             1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle2)
-        and: 'the composite state cm handle state is now READY'
-            assert compositeState2.getCmHandleState() == CmHandleState.READY
-        and: 'the second cm handle state is updated'
-            1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle-2', compositeState2)
+        then: 'the state handler is called for the second cm handle'
+            1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle2, CmHandleState.READY)
     }
 
     def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handle with failure'() {
@@ -93,13 +89,10 @@ class ModuleSyncWatchdogSpec extends Specification {
             1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState
         and: 'module sync service attempts to sync the cm handle and throws an exception'
             1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
-        and: 'the composite state cm handle state is now LOCKED'
-            assert compositeState.getCmHandleState() == CmHandleState.LOCKED
         and: 'update lock reason, details and attempts is invoked'
             1 * mockSyncUtils.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.LOCKED_MODULE_SYNC_FAILED ,'some exception')
-        and: 'the cm handle state is updated'
-            1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle', compositeState)
-
+        and: 'the state handler is called to update the state to LOCKED'
+            1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle, CmHandleState.LOCKED)
     }
 
     def 'Schedule a Cm-Handle Sync with condition #scenario '() {
@@ -116,7 +109,7 @@ class ModuleSyncWatchdogSpec extends Specification {
         when: 'module sync poll is executed'
             objectUnderTest.executeLockedCmHandlePoll()
         then: 'the first cm handle is updated to state "ADVISED" from "READY"'
-            expectedNumberOfInvocationsToSaveCmHandleState * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.id, compositeState)
+            expectedNumberOfInvocationsToSaveCmHandleState * mockLcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle, CmHandleState.ADVISED)
         where:
             scenario                        | isReadyForRetry         || expectedNumberOfInvocationsToSaveCmHandleState
             'retry locked cm handle once'   | [true, false]           || 1