Enable/Disable Data Sync for Cm Handle 86/129986/11
authorDylanB95EST <dylan.byrne@est.tech>
Tue, 19 Jul 2022 10:36:10 +0000 (11:36 +0100)
committerDylanB95EST <dylan.byrne@est.tech>
Thu, 28 Jul 2022 14:34:27 +0000 (15:34 +0100)
-Create API Which will enable/disable data sync enabled flag
-Default functionality of module sync watchdog is to set to false
-Remove global config param
-Will set initial sync state based on data sync enabled flag
-Throws an Exception if the same data sync enabled flag tries
to be set
-Throws Exception if state is not in READY
-Data Sync enabled must be true to complete data sync process
- Delete all resource data within fragment table related
to synced cm handle when data sync is set to false

Issue-ID: CPS-1133
Change-Id: Ib47bbd8293f083c1d705d91bd0def74e6a105c72
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
20 files changed:
cps-application/src/main/resources/application.yml
cps-ncmp-rest-stub/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
cps-ncmp-rest/docs/openapi/components.yaml
cps-ncmp-rest/docs/openapi/ncmp.yml
cps-ncmp-rest/docs/openapi/openapi.yml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.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/DataSyncWatchdog.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/LcmEventsCmHandleStateHandlerImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsPublisherSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/DataSyncSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy

index dd83795..6bbe80b 100644 (file)
@@ -164,8 +164,4 @@ timers:
     locked-modules-sync:\r
         sleep-time-ms: 300000\r
     cm-handle-data-sync:\r
-        sleep-time-ms: 30000\r
-\r
-data-sync:\r
-    cache:\r
-        enabled: false
\ No newline at end of file
+        sleep-time-ms: 30000
\ No newline at end of file
index d8e48be..67af6f1 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Bell Canada
+ *  Modifications Copyright (c) 2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -85,6 +86,12 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
         return ResponseEntity.ok(restOutputCmHandles);
     }
 
+    @Override
+    public ResponseEntity<Object> setDataSyncEnabledFlagForCmHandle(final String cmHandleId,
+                                                                final Boolean dataSyncEnabled) {
+        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
     @Override
     public ResponseEntity<List<String>> searchCmHandleIds(
         final CmHandleQueryParameters cmHandleQueryParameters) {
index 2cb9d89..a717921 100644 (file)
@@ -389,6 +389,14 @@ components:
       schema:
         type: string
         example: my-cm-handle
+    dataSyncEnabled:
+      name: dataSyncEnabled
+      in: query
+      description: Is used to enable or disable the data synchronization flag
+      required: true
+      schema:
+        type: boolean
+        example: true
     xpathInQuery:
       name: xpath
       in: query
index aaf0d6a..401c1ea 100755 (executable)
@@ -408,4 +408,28 @@ searchCmHandleIds:
       404:
         $ref: 'components.yaml#/components/responses/NotFound'
       500:
-        $ref: 'components.yaml#/components/responses/InternalServerError'
\ No newline at end of file
+        $ref: 'components.yaml#/components/responses/InternalServerError'
+
+setDataSyncEnabledFlag:
+  put:
+    tags:
+      - network-cm-proxy
+    summary: Set the Data Sync Enabled Flag
+    description: Set the data sync enabled flag to true or false for a specified Cm-Handle. This will in turn set the data sync state to UNSYNCHRONIZED and NONE_REQUESTED respectfully.
+    operationId: setDataSyncEnabledFlagForCmHandle
+    parameters:
+      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+      - $ref: 'components.yaml#/components/parameters/dataSyncEnabled'
+    responses:
+      200:
+        $ref: 'components.yaml#/components/responses/Ok'
+      400:
+        $ref: 'components.yaml#/components/responses/BadRequest'
+      401:
+        $ref: 'components.yaml#/components/responses/Unauthorized'
+      403:
+        $ref: 'components.yaml#/components/responses/Forbidden'
+      500:
+        $ref: 'components.yaml#/components/responses/InternalServerError'
+      502:
+        $ref: 'components.yaml#/components/responses/BadGateway'
\ No newline at end of file
index 35be59a..8e02066 100755 (executable)
@@ -52,3 +52,6 @@ paths:
 
   /v1/ch/{cm-handle}/state:
     $ref: 'ncmp.yml#/getCmHandleStateById'
+
+  /v1/ch/{cm-handle}/data-sync:
+    $ref: 'ncmp.yml#/setDataSyncEnabledFlag'
index b204871..d2ed393 100755 (executable)
@@ -320,6 +320,20 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
         return new ResponseEntity<>(restModuleReferences, HttpStatus.OK);
     }
 
+    /**
+     * Set the data sync enabled flag, along with the data sync state for the specified cm handle.
+     *
+     * @param cmHandleId cm handle id
+     * @param dataSyncEnabledFlag data sync enabled flag
+     * @return response entity ok if request is successful
+     */
+    @Override
+    public ResponseEntity<Object> setDataSyncEnabledFlagForCmHandle(final String cmHandleId,
+                                                                final Boolean dataSyncEnabledFlag) {
+        networkCmProxyDataService.setDataSyncEnabled(cmHandleId, dataSyncEnabledFlag);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+
     private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) {
         final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle();
         final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties();
index 23263c9..fde3087 100644 (file)
@@ -423,6 +423,20 @@ class NetworkCmProxyControllerSpec extends Specification {
             response.status == HttpStatus.OK.value()
     }
 
+    def 'Set the data sync enabled based on the cm handle id and the data sync flag is #scenario' () {
+        when: 'the set data sync enabled request is invoked'
+            def response = mvc.perform(put("$ncmpBasePathV1/ch/some-cm-handle-id/data-sync?dataSyncEnabled=" + dataSyncEnabledFlag))
+                    .andReturn().response
+        then: 'method to set data sync enabled is called'
+            1 * mockNetworkCmProxyDataService.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
+        and: 'the response returns an OK http code'
+            response.status == HttpStatus.OK.value()
+        where: 'the following parameters are used'
+        scenario     |  dataSyncEnabledFlag
+        'enabled'    |  true
+        'disabled'   |  false
+    }
+
     def dataStores() {
         DataStores.builder()
             .operationalDataStore(Operational.builder()
index ea27d4a..3295a6e 100644 (file)
@@ -154,4 +154,12 @@ public interface NetworkCmProxyDataService {
      * @return collection of cm handle ids
      */
     Set<String> executeCmHandleIdSearch(CmHandleQueryApiParameters cmHandleQueryApiParameters);
+
+    /**
+     * Set the data sync enabled flag, along with the data sync state to true or false based on the cm handle id.
+     *
+     * @param cmHandleId cm handle id
+     * @param dataSyncEnabled data sync enabled flag
+     */
+    void setDataSyncEnabled(String cmHandleId, boolean dataSyncEnabled);
 }
index 8d32c1a..d5bf263 100755 (executable)
@@ -26,6 +26,7 @@ package org.onap.cps.ncmp.api.impl;
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
 import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateCmHandleQueryParameters;
 
+import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -35,6 +36,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.api.CpsDataService;
 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService;
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
 import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler;
@@ -44,6 +46,8 @@ import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 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.CompositeStateUtils;
+import org.onap.cps.ncmp.api.inventory.DataStoreSyncState;
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
 import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
@@ -52,6 +56,7 @@ import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
 import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.spi.exceptions.AlreadyDefinedException;
+import org.onap.cps.spi.exceptions.CpsException;
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
 import org.onap.cps.spi.exceptions.DataValidationException;
 import org.onap.cps.spi.model.CmHandleQueryServiceParameters;
@@ -79,6 +84,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler;
 
+    private final CpsDataService cpsDataService;
+
     @Override
     public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
             final DmiPluginRegistration dmiPluginRegistration) {
@@ -181,6 +188,36 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         return networkCmProxyCmHandlerQueryService.queryCmHandleIds(cmHandleQueryServiceParameters);
     }
 
+    /**
+     * 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 dataSyncEnabled data sync enabled flag
+     */
+    @Override
+    public void setDataSyncEnabled(final String cmHandleId, final boolean dataSyncEnabled) {
+        CpsValidator.validateNameCharacters(cmHandleId);
+        final CompositeState compositeState = inventoryPersistence
+            .getCmHandleState(cmHandleId);
+        if (compositeState.getDataSyncEnabled().equals(dataSyncEnabled)) {
+            log.info("Data-Sync Enabled flag is already: {} ", dataSyncEnabled);
+        } else if (compositeState.getCmHandleState() != CmHandleState.READY) {
+            throw new CpsException("State mismatch exception.", "Cm-Handle not in READY state. Cm handle state is: "
+                + compositeState.getCmHandleState());
+        } else {
+            final DataStoreSyncState dataStoreSyncState = compositeState.getDataStores()
+                .getOperationalDataStore().getDataStoreSyncState();
+            if (!dataSyncEnabled && dataStoreSyncState == DataStoreSyncState.SYNCHRONIZED) {
+                cpsDataService.deleteDataNode("NFP-Operational", cmHandleId,
+                    "/netconf-state", OffsetDateTime.now());
+            }
+            CompositeStateUtils.setDataSyncEnabledFlagWithDataSyncState(dataSyncEnabled, compositeState);
+            inventoryPersistence.saveCmHandleState(cmHandleId,
+                compositeState);
+        }
+    }
+
     /**
      * Retrieve cm handle details for a given cm handle.
      *
index bd47bea..9027a6e 100644 (file)
@@ -34,7 +34,6 @@ import org.onap.cps.ncmp.api.inventory.CompositeStateUtils;
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.ncmp.cmhandle.event.lcm.LcmEvent;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 @Slf4j
@@ -46,14 +45,10 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState
     private final LcmEventsCreator lcmEventsCreator;
     private final LcmEventsService lcmEventsService;
 
-    @Value("${data-sync.cache.enabled:false}")
-    private boolean isGlobalDataSyncCacheEnabled;
-
 
     @Override
     public void updateCmHandleState(final YangModelCmHandle yangModelCmHandle,
             final CmHandleState targetCmHandleState) {
-
         if (yangModelCmHandle.getCompositeState().getCmHandleState() == targetCmHandleState) {
             log.debug("CmHandle with id : {} already in state : {}", yangModelCmHandle.getId(), targetCmHandleState);
         } else {
@@ -67,7 +62,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState
             final CmHandleState targetCmHandleState) {
 
         if (READY == targetCmHandleState) {
-            CompositeStateUtils.setCompositeStateToReadyWithInitialDataStoreSyncState(isGlobalDataSyncCacheEnabled)
+            CompositeStateUtils.setCompositeStateToReadyWithInitialDataStoreSyncState()
                     .accept(yangModelCmHandle.getCompositeState());
             inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState());
         } else if (ADVISED == targetCmHandleState) {
index a0fc0c3..d6a3330 100644 (file)
@@ -32,6 +32,7 @@ public class CompositeStateBuilder {
     private LockReason lockReason;
     private DataStores datastores;
     private String lastUpdatedTime;
+    private Boolean dataSyncEnabled;
 
     /**
      * To create the {@link CompositeState}.
@@ -44,6 +45,7 @@ public class CompositeStateBuilder {
         compositeState.setLockReason(lockReason);
         compositeState.setDataStores(datastores);
         compositeState.setLastUpdateTime(lastUpdatedTime);
+        compositeState.setDataSyncEnabled(dataSyncEnabled);
         return compositeState;
     }
 
@@ -115,6 +117,9 @@ public class CompositeStateBuilder {
         this.cmHandleState = CmHandleState.valueOf((String) dataNode.getLeaves()
             .get("cm-handle-state"));
         this.lastUpdatedTime = (String) dataNode.getLeaves().get("last-update-time");
+        if (this.cmHandleState == CmHandleState.READY) {
+            this.dataSyncEnabled = (Boolean) dataNode.getLeaves().get("data-sync-enabled");
+        }
         for (final DataNode stateChildNode : dataNode.getChildDataNodes()) {
             if (stateChildNode.getXpath().endsWith("/lock-reason")) {
                 this.lockReason = getLockReason(stateChildNode);
index 506bd11..54ca68a 100644 (file)
@@ -49,10 +49,9 @@ public class CompositeStateUtils {
      *
      * @return Updated CompositeState
      */
-    public static Consumer<CompositeState> setCompositeStateToReadyWithInitialDataStoreSyncState(
-            final boolean isGlobalDataSyncCacheEnabled) {
+    public static Consumer<CompositeState> setCompositeStateToReadyWithInitialDataStoreSyncState() {
         return compositeState -> {
-            compositeState.setDataSyncEnabled(isGlobalDataSyncCacheEnabled);
+            compositeState.setDataSyncEnabled(false);
             compositeState.setCmHandleState(CmHandleState.READY);
             final CompositeState.Operational operational =
                     getInitialDataStoreSyncState(compositeState.getDataSyncEnabled());
@@ -62,6 +61,27 @@ public class CompositeStateUtils {
         };
     }
 
+    /**
+     * Set the data sync enabled flag, along with the data store sync state based on this flag.
+     *
+     * @param dataSyncEnabled data sync enabled flag
+     * @param compositeState cm handle composite state
+     */
+    public static void setDataSyncEnabledFlagWithDataSyncState(final boolean dataSyncEnabled,
+                                                               final CompositeState compositeState) {
+        compositeState.setDataSyncEnabled(dataSyncEnabled);
+        final CompositeState.Operational operational = getInitialDataStoreSyncState(dataSyncEnabled);
+        final CompositeState.DataStores dataStores =
+            CompositeState.DataStores.builder().operationalDataStore(operational).build();
+        compositeState.setDataStores(dataStores);
+    }
+
+    /**
+     * Get initial data sync state based on data sync enabled boolean flag.
+     *
+     * @param dataSyncEnabled data sync enabled boolean flag
+     * @return the data store sync state
+     */
     private static CompositeState.Operational getInitialDataStoreSyncState(final boolean dataSyncEnabled) {
         final DataStoreSyncState dataStoreSyncState =
                 dataSyncEnabled ? DataStoreSyncState.UNSYNCHRONIZED : DataStoreSyncState.NONE_REQUESTED;
index adfa33a..395fb01 100644 (file)
@@ -58,6 +58,9 @@ public class DataSyncWatchdog {
             final String resourceData = syncUtils.getResourceData(cmHandleId);
             if (resourceData == null) {
                 log.debug("Error accessing the node for Cm-Handle: {}", cmHandleId);
+            } else if (unSynchronizedReadyCmHandle.getCompositeState().getDataSyncEnabled().equals(false)) {
+                log.debug("Error: data sync enabled for {} must be true."
+                    + "Data sync enabled is currently set to false", cmHandleId);
             } else {
                 cpsDataService.saveData("NFP-Operational", cmHandleId,
                         resourceData, OffsetDateTime.now());
index c71f68f..37bd1ed 100644 (file)
@@ -32,7 +32,6 @@ 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.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
@@ -47,9 +46,6 @@ public class ModuleSyncWatchdog {
 
     private final ModuleSyncService moduleSyncService;
 
-    @Value("${data-sync.cache.enabled:false}")
-    private boolean isGlobalDataSyncCacheEnabled;
-
     private final ConcurrentMap<String, Boolean> moduleSyncSemaphoreMap;
 
     /**
@@ -107,9 +103,9 @@ public class ModuleSyncWatchdog {
 
     private Consumer<CompositeState> setCompositeStateToReadyWithInitialDataStoreSyncState() {
         return compositeState -> {
-            compositeState.setDataSyncEnabled(isGlobalDataSyncCacheEnabled);
+            compositeState.setDataSyncEnabled(false);
             compositeState.setCmHandleState(CmHandleState.READY);
-            final CompositeState.Operational operational = getDataStoreSyncState(compositeState.getDataSyncEnabled());
+            final CompositeState.Operational operational = getDataStoreSyncState();
             final CompositeState.DataStores dataStores = CompositeState.DataStores.builder()
                     .operationalDataStore(operational)
                     .build();
@@ -126,9 +122,8 @@ public class ModuleSyncWatchdog {
         compositeState.setLockReason(lockReason);
     }
 
-    private CompositeState.Operational getDataStoreSyncState(final boolean dataSyncEnabled) {
-        final DataStoreSyncState dataStoreSyncState = dataSyncEnabled
-                ? DataStoreSyncState.UNSYNCHRONIZED : DataStoreSyncState.NONE_REQUESTED;
+    private CompositeState.Operational getDataStoreSyncState() {
+        final DataStoreSyncState dataStoreSyncState = DataStoreSyncState.NONE_REQUESTED;
         return CompositeState.Operational.builder().dataStoreSyncState(dataStoreSyncState).build();
     }
 
index 1ee1ad2..2aa08b8 100644 (file)
@@ -22,6 +22,7 @@
 package org.onap.cps.ncmp.api.impl
 
 import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.api.CpsDataService
 import org.onap.cps.api.CpsModuleService
 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService
 import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler
@@ -60,6 +61,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
     def mockInventoryPersistence = Mock(InventoryPersistence)
     def stubbedNetworkCmProxyCmHandlerQueryService = Stub(NetworkCmProxyCmHandlerQueryService)
     def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
+    def mockCpsDataService = Mock(CpsDataService)
     def objectUnderTest = getObjectUnderTest()
 
     def 'DMI Registration: Create, Update & Delete operations are processed in the right order'() {
@@ -351,6 +353,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
     def getObjectUnderTest() {
         return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations,
             mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, stubbedNetworkCmProxyCmHandlerQueryService,
-                mockLcmEventsCmHandleStateHandler))
+                mockLcmEventsCmHandleStateHandler, mockCpsDataService))
     }
 }
index d112557..a372def 100644 (file)
@@ -34,6 +34,7 @@ import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
 import org.onap.cps.ncmp.api.models.ConditionApiProperties
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.spi.exceptions.CpsException
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.spi.model.CmHandleQueryServiceParameters
 import spock.lang.Shared
@@ -79,7 +80,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             nullNetworkCmProxyDataServicePropertyHandler,
             mockInventoryPersistence,
             mockCpsCmHandlerQueryService,
-            mockLcmEventsCmHandleStateHandler)
+            mockLcmEventsCmHandleStateHandler,
+            mockCpsDataService)
 
     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
 
@@ -311,14 +313,6 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
     }
 
-
-    def dataStores() {
-        CompositeState.DataStores.builder()
-                .operationalDataStore(CompositeState.Operational.builder()
-                        .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
-                        .lastSyncTime('some-timestamp').build()).build()
-    }
-
     def 'Execute cm handle search'() {
         given: 'valid CmHandleQueryApiParameters input'
             def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
@@ -335,4 +329,51 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
         then: 'result is the same collection as returned by the CPS Data Service'
             assert result.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == ['cm-handle-id-1'] as Set
     }
+
+    def 'Set Cm Handle Data Sync Enabled Flag where data sync flag is  #scenario'() {
+        given: 'an existing cm handle composite state'
+            def compositeState = new CompositeState(cmHandleState: CmHandleState.READY, dataSyncEnabled: initialDataSyncEnabledFlag,
+                dataStores: CompositeState.DataStores.builder()
+                    .operationalDataStore(CompositeState.Operational.builder()
+                        .dataStoreSyncState(initialDataSyncState)
+                        .build()).build())
+        and: 'get cm handle state returns the composite state for the given cm handle id'
+            mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
+        when: 'set data sync enabled is called with the data sync enabled flag set to #dataSyncEnabledFlag'
+            objectUnderTest.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
+        then: 'the data sync enabled flag is set to #dataSyncEnabled'
+            compositeState.dataSyncEnabled == dataSyncEnabledFlag
+        and: 'the data store sync state is set to #expectedDataStoreSyncState'
+            compositeState.dataStores.operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState
+        and: 'the cps data service to delete data nodes is invoked the expected number of times'
+            deleteDataNodeExpectedNumberOfInvocation * mockCpsDataService.deleteDataNode('NFP-Operational', 'some-cm-handle-id', '/netconf-state', _)
+        and: 'the inventory persistence service to update node leaves is called with the correct values'
+            saveCmHandleStateExpectedNumberOfInvocations * mockInventoryPersistence.saveCmHandleState('some-cm-handle-id', compositeState)
+        where: 'the following data sync enabled flag is used'
+            scenario                                              | dataSyncEnabledFlag | initialDataSyncEnabledFlag | initialDataSyncState               || expectedDataStoreSyncState         | deleteDataNodeExpectedNumberOfInvocation | saveCmHandleStateExpectedNumberOfInvocations
+            'enabled'                                             | true                | false                      | DataStoreSyncState.NONE_REQUESTED  || DataStoreSyncState.UNSYNCHRONIZED  | 0                                        | 1
+            'disabled'                                            | false               | true                       | DataStoreSyncState.UNSYNCHRONIZED  || DataStoreSyncState.NONE_REQUESTED  | 0                                        | 1
+            'disabled where sync-state is currently SYNCHRONIZED' | false               | true                       | DataStoreSyncState.SYNCHRONIZED    || DataStoreSyncState.NONE_REQUESTED  | 1                                        | 1
+            'is set to existing flag state'                       | true                | true                       | DataStoreSyncState.UNSYNCHRONIZED  || DataStoreSyncState.UNSYNCHRONIZED  | 0                                        | 0
+    }
+
+    def 'Set cm Handle Data Sync Enabled flag with following cm handle not in ready state exception' () {
+        given: 'a cm handle composite state'
+            def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, dataSyncEnabled: false)
+        and: 'get cm handle state returns the composite state for the given cm handle id'
+            mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
+        when: 'set data sync enabled is called with the data sync enabled flag set to true'
+            objectUnderTest.setDataSyncEnabled('some-cm-handle-id', true)
+        then: 'the expected exception is thrown'
+            thrown(CpsException)
+        and: 'the inventory persistence service to update node leaves is not invoked'
+            0 * mockInventoryPersistence.saveCmHandleState(_, _)
+    }
+
+    def dataStores() {
+        CompositeState.DataStores.builder()
+            .operationalDataStore(CompositeState.Operational.builder()
+                .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
+                .lastSyncTime('some-timestamp').build()).build()
+    }
 }
index b4e57c7..b343679 100644 (file)
@@ -94,29 +94,25 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification {
             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _)
     }
 
-    def 'Update and Publish Events on State Change to READY with #scenario'() {
+    def 'Update and Publish Events on State Change to READY'() {
         given: 'Cm Handle represented as YangModelCmHandle'
             compositeState = new CompositeState(cmHandleState: ADVISED)
             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
         and: 'global sync flag is set'
-            objectUnderTest.isGlobalDataSyncCacheEnabled = dataSyncCacheEnabled
+            compositeState.setDataSyncEnabled(false)
         when: 'update cmhandle state is invoked'
             objectUnderTest.updateCmHandleState(yangModelCmHandle, READY)
         then: 'state is saved using inventory persistence with expected dataSyncState'
             1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> {
                 args-> {
                     def result = (args[1] as CompositeState)
-                    assert result.dataSyncEnabled == dataSyncCacheEnabled
-                    assert result.dataStores.operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState
+                    assert result.dataSyncEnabled == false
+                    assert result.dataStores.operationalDataStore.dataStoreSyncState == DataStoreSyncState.NONE_REQUESTED
 
                 }
             }
         and: 'event service is called to publish event'
             1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _)
-        where:
-            scenario                         | dataSyncCacheEnabled || expectedDataStoreSyncState
-            'data sync cache enabled'        | true                 || DataStoreSyncState.UNSYNCHRONIZED
-            'data sync cache is not enabled' | false                || DataStoreSyncState.NONE_REQUESTED
     }
 
     def 'Update cmHandle state to "DELETING"' (){
index f2cd2b5..c7e6b6d 100644 (file)
@@ -22,7 +22,6 @@ package org.onap.cps.ncmp.api.impl.event.lcm
 
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.apache.kafka.clients.consumer.KafkaConsumer
-import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsPublisher
 import org.onap.cps.ncmp.api.utils.MessagingSpec
 import org.onap.cps.ncmp.utils.TestUtils
 import org.onap.cps.utils.JsonObjectMapper
index 20880ca..650a779 100644 (file)
@@ -26,6 +26,7 @@ import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.ncmp.api.inventory.CompositeState
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
 import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
+import spock.lang.Shared
 import spock.lang.Specification
 
 class DataSyncSpec extends Specification {
@@ -36,6 +37,7 @@ class DataSyncSpec extends Specification {
 
     def mockSyncUtils = Mock(SyncUtils)
 
+    @Shared
     def jsonString = '{"stores:bookstore":{"categories":[{"code":"01"}]}}'
 
     def objectUnderTest = new DataSyncWatchdog(mockInventoryPersistence, mockCpsDataService, mockSyncUtils)
@@ -48,7 +50,7 @@ class DataSyncSpec extends Specification {
 
     def 'Schedule Data Sync for Cm Handle State in READY and Operational Sync State in UNSYNCHRONIZED'() {
         given: 'sample resource data'
-            def resourceData = jsonString;
+            def resourceData = jsonString
         and: 'sync utilities return a cm handle twice'
             mockSyncUtils.getAnUnSynchronizedReadyCmHandle() >>> [yangModelCmHandle1, yangModelCmHandle2, null]
         when: 'data sync poll is executed'
@@ -71,18 +73,24 @@ class DataSyncSpec extends Specification {
             1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle-2', compositeState)
     }
 
-    def 'Schedule Data Sync for Cm Handle State in READY and Operational Sync State in UNSYNCHRONIZED which return empty data from Node'() {
-        given: 'cm handles in an ready state and operational sync state in unsynchronized'
-        and: 'sync utilities return a cm handle twice'
-            mockSyncUtils.getAnUnSynchronizedReadyCmHandle() >>> [yangModelCmHandle1, null]
+    def 'Schedule Data Sync for Cm Handle State in READY and Operational Sync State in UNSYNCHRONIZED which return empty data from Node because #scenario'() {
+        given: 'a yang model cm handle'
+            def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', compositeState: new CompositeState(dataSyncEnabled: dataSyncEnabled))
+        and: 'sync utilities returns a single cm handle'
+            mockSyncUtils.getAnUnSynchronizedReadyCmHandle() >>> [yangModelCmHandle, null]
         when: 'data sync poll is executed'
             objectUnderTest.executeUnSynchronizedReadyCmHandlePoll()
         then: 'the inventory persistence cm handle returns a composite state for the first cm handle'
-            1 * mockInventoryPersistence.getCmHandleState('some-cm-handle-1') >> compositeState
+            1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState
         and: 'the sync util returns first resource data'
-            1 * mockSyncUtils.getResourceData('some-cm-handle-1') >> null
+            1 * mockSyncUtils.getResourceData('some-cm-handle') >> resourceData
         and: 'the cm-handle data is not saved'
             0 * mockCpsDataService.saveData('NFP-Operational', 'some-cm-handle-1', jsonString, _)
+        where:
+            scenario                                             | dataSyncEnabled | resourceData
+            'data sync is not enabled'                           | false           | jsonString
+            'resource data is null'                              | true            | null
+            'data sync is not enabled and resource data is null' | false           | null
     }
 
     def createSampleYangModelCmHandle(cmHandleId) {
@@ -92,7 +100,7 @@ class DataSyncSpec extends Specification {
 
     def getCompositeState() {
         def cmHandleState = CmHandleState.READY
-        def compositeState = new CompositeState(cmHandleState: cmHandleState)
+        def compositeState = new CompositeState(cmHandleState: cmHandleState, dataSyncEnabled: true)
         compositeState.setDataStores(CompositeState.DataStores.builder()
             .operationalDataStore(CompositeState.Operational.builder().dataStoreSyncState(DataStoreSyncState.SYNCHRONIZED)
                 .build()).build())
index 7455438..41f2160 100644 (file)
@@ -47,13 +47,12 @@ class ModuleSyncWatchdogSpec extends Specification {
 
     def objectUnderTest = new ModuleSyncWatchdog(mockInventoryPersistence, mockSyncUtils, mockModuleSyncService, stubbedMap as ConcurrentHashMap)
 
-    def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles where #scenario'() {
+    def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles'() {
         given: 'cm handles in an advised state and a data sync state'
             def compositeState1 = new CompositeState(cmHandleState: cmHandleState)
             def compositeState2 = new CompositeState(cmHandleState: cmHandleState)
             def yangModelCmHandle1 = new YangModelCmHandle(id: 'some-cm-handle', compositeState: compositeState1)
             def yangModelCmHandle2 = new YangModelCmHandle(id: 'some-cm-handle-2', compositeState: compositeState2)
-            objectUnderTest.isGlobalDataSyncCacheEnabled = dataSyncCacheEnabled
         and: 'sync utilities return a cm handle twice'
             mockSyncUtils.getAdvisedCmHandles() >> [yangModelCmHandle1, yangModelCmHandle2]
         when: 'module sync poll is executed'
@@ -66,8 +65,10 @@ class ModuleSyncWatchdogSpec extends Specification {
             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 == expectedDataStoreSyncState
+            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'
@@ -78,10 +79,6 @@ class ModuleSyncWatchdogSpec extends Specification {
             assert compositeState2.getCmHandleState() == CmHandleState.READY
         and: 'the second cm handle state is updated'
             1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle-2', compositeState2)
-        where:
-            scenario                         | dataSyncCacheEnabled  || expectedDataStoreSyncState
-            'data sync cache enabled'        | true                  || DataStoreSyncState.UNSYNCHRONIZED
-            'data sync cache is not enabled' | false                 || DataStoreSyncState.NONE_REQUESTED
     }
 
     def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handle with failure'() {