From 9fdaf6c0f472cad13ade1469458822d468fd2d6d Mon Sep 17 00:00:00 2001 From: sourabh_sourabh Date: Mon, 25 Jul 2022 09:49:40 +0100 Subject: De-registration: send event(s) using central state - refactored method "parseAndRemoveCmHandlesInDmiRegistration" - added method to send events for DELETING and DELETED - introduced private method in state handler - updated unit tests for registration spec - added unit test to cover new private method in state handler Issue-ID: CPS-1003 Signed-off-by: emaclee Change-Id: Ifc1d1e94b7103d85b6352b196edf7075257c211a Signed-off-by: sourabh_sourabh --- .../api/impl/NetworkCmProxyDataServiceImpl.java | 34 ++++++++++----- .../lcm/LcmEventsCmHandleStateHandlerImpl.java | 19 ++++++-- ...rkCmProxyDataServiceImplRegistrationSpec.groovy | 21 ++++++--- .../impl/NetworkCmProxyDataServiceImplSpec.groovy | 11 ++++- .../LcmEventsCmHandleStateHandlerImplSpec.groovy | 51 +++++++++++++++++----- 5 files changed, 102 insertions(+), 34 deletions(-) (limited to 'cps-ncmp-service') diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index 16b9a66f4e..8d32c1ade5 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -37,6 +37,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; +import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; import org.onap.cps.ncmp.api.impl.operations.DmiOperations; import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; @@ -76,6 +77,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private final NetworkCmProxyCmHandlerQueryService networkCmProxyCmHandlerQueryService; + private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler; + @Override public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule( final DmiPluginRegistration dmiPluginRegistration) { @@ -262,32 +265,41 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final List tobeRemovedCmHandles) { final List cmHandleRegistrationResponses = new ArrayList<>(tobeRemovedCmHandles.size()); - for (final String cmHandle : tobeRemovedCmHandles) { + for (final String cmHandleId : tobeRemovedCmHandles) { try { - CpsValidator.validateNameCharacters(cmHandle); - inventoryPersistence.deleteSchemaSetWithCascade(cmHandle); - inventoryPersistence.deleteListOrListElement("/dmi-registry/cm-handles[@id='" + cmHandle + "']"); - cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandle)); + CpsValidator.validateNameCharacters(cmHandleId); + final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); + lcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle, + CmHandleState.DELETING); + deleteSchemaSetAndListElementByCmHandleId(cmHandleId); + cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); + lcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle, + CmHandleState.DELETED); } catch (final DataNodeNotFoundException dataNodeNotFoundException) { log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", - cmHandle, dataNodeNotFoundException.getMessage()); + cmHandleId, dataNodeNotFoundException.getMessage()); cmHandleRegistrationResponses.add(CmHandleRegistrationResponse - .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_DOES_NOT_EXIST)); + .createFailureResponse(cmHandleId, RegistrationError.CM_HANDLE_DOES_NOT_EXIST)); } catch (final DataValidationException dataValidationException) { log.error("Unable to de-register cm-handle id: {}, caused by: {}", - cmHandle, dataValidationException.getMessage()); + cmHandleId, dataValidationException.getMessage()); cmHandleRegistrationResponses.add(CmHandleRegistrationResponse - .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_INVALID_ID)); + .createFailureResponse(cmHandleId, RegistrationError.CM_HANDLE_INVALID_ID)); } catch (final Exception exception) { log.error("Unable to de-register cm-handle id : {} , caused by : {}", - cmHandle, exception.getMessage()); + cmHandleId, exception.getMessage()); cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandle, exception)); + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); } } return cmHandleRegistrationResponses; } + private void deleteSchemaSetAndListElementByCmHandleId(final String cmHandleId) { + inventoryPersistence.deleteSchemaSetWithCascade(cmHandleId); + inventoryPersistence.deleteListOrListElement("/dmi-registry/cm-handles[@id='" + cmHandleId + "']"); + } + private CmHandleRegistrationResponse registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) { try { inventoryPersistence.saveCmHandle(yangModelCmHandle); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java index 650251f5ae..bd47bea73a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImpl.java @@ -21,6 +21,7 @@ package org.onap.cps.ncmp.api.impl.event.lcm; import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED; +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED; import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED; import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY; @@ -75,11 +76,11 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState } else { registerNewCmHandle(yangModelCmHandle); } + } else if (DELETED == targetCmHandleState) { + setCmHandleState(yangModelCmHandle, targetCmHandleState); } else { - CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState()); - inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()); + updateAndSaveCmHandleState(yangModelCmHandle, targetCmHandleState); } - } private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) { @@ -88,7 +89,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState } private void registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) { - CompositeStateUtils.setCompositeState(ADVISED).accept(yangModelCmHandle.getCompositeState()); + setCmHandleState(yangModelCmHandle, ADVISED); inventoryPersistence.saveCmHandle(yangModelCmHandle); } @@ -99,4 +100,14 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState final LcmEvent lcmEvent = lcmEventsCreator.populateLcmEvent(cmHandleId); lcmEventsService.publishLcmEvent(cmHandleId, lcmEvent); } + + private void updateAndSaveCmHandleState(final YangModelCmHandle yangModelCmHandle, + final CmHandleState targetCmHandleState) { + setCmHandleState(yangModelCmHandle, targetCmHandleState); + inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()); + } + + private void setCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState) { + CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState()); + } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index dccba0be48..1ee1ad2f60 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -24,6 +24,7 @@ package org.onap.cps.ncmp.api.impl import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService +import org.onap.cps.ncmp.api.impl.event.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.impl.exception.DmiRequestException import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle @@ -58,6 +59,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler) def mockInventoryPersistence = Mock(InventoryPersistence) def stubbedNetworkCmProxyCmHandlerQueryService = Stub(NetworkCmProxyCmHandlerQueryService) + def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler) def objectUnderTest = getObjectUnderTest() def 'DMI Registration: Create, Update & Delete operations are processed in the right order'() { @@ -249,7 +251,11 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { { if (!schemaSetExist) { throw new SchemaSetNotFoundException("", "") } } when: 'registration is updated to delete cmhandle' def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - then: 'delete list or list element is called' + then: 'the cmHandle state is updated to "DELETING"' + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, CmHandleState.DELETING) + and: 'method to delete relevant schema set is called once' + 1 * mockInventoryPersistence.deleteSchemaSetWithCascade(_) + and: 'method to delete relevant list/list element is called once' 1 * mockInventoryPersistence.deleteListOrListElement(_) and: 'successful response is received' assert response.getRemovedCmHandles().size() == 1 @@ -257,6 +263,8 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { assert it.status == Status.SUCCESS assert it.cmHandle == 'cmhandle' } + and: 'the cmHandle state is updated to "DELETED"' + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, CmHandleState.DELETED) where: scenario | schemaSetExist 'schema-set exists and can be deleted successfully' | true @@ -303,6 +311,8 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { noExceptionThrown() and: 'cm-handle is not deleted' 0 * mockInventoryPersistence.deleteListOrListElement(_) + and: 'the cmHandle state is not updated to "DELETED"' + 0 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, CmHandleState.DELETED) and: 'a failure response is received' assert response.getRemovedCmHandles().size() == 1 with(response.getRemovedCmHandles().get(0)) { @@ -321,9 +331,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { mockInventoryPersistence.deleteListOrListElement(_) >> { throw deleteListElementException } when: 'registration is updated to delete cmhandle' def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - then: 'no exception is thrown' - noExceptionThrown() - and: 'a failure response is received' + then: 'a failure response is received' assert response.getRemovedCmHandles().size() == 1 with(response.getRemovedCmHandles().get(0)) { assert it.status == Status.FAILURE @@ -331,6 +339,8 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { assert it.registrationError == expectedError assert it.errorText == expectedErrorText } + and: 'the cm handle state is not updated to "DELETED"' + 0 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, CmHandleState.DELETED) where: scenario | cmHandleId | deleteListElementException || expectedError | expectedErrorText 'cm-handle does not exist' | 'cmhandle' | new DataNodeNotFoundException("", "", "") || CM_HANDLE_DOES_NOT_EXIST | 'cm-handle does not exist' @@ -340,6 +350,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def getObjectUnderTest() { return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations, - mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, stubbedNetworkCmProxyCmHandlerQueryService)) + mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, stubbedNetworkCmProxyCmHandlerQueryService, + mockLcmEventsCmHandleStateHandler)) } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index 3febaa51bd..d112557671 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -23,6 +23,7 @@ package org.onap.cps.ncmp.api.impl import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService +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 @@ -63,6 +64,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) def mockDmiPluginRegistration = Mock(DmiPluginRegistration) def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandlerQueryService) + def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler) def NO_TOPIC = null def NO_REQUEST_ID = null @@ -71,8 +73,13 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { @Shared def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id') - def objectUnderTest = new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations, - nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCpsCmHandlerQueryService) + def objectUnderTest = new NetworkCmProxyDataServiceImpl( + spiedJsonObjectMapper, + mockDmiDataOperations, + nullNetworkCmProxyDataServicePropertyHandler, + mockInventoryPersistence, + mockCpsCmHandlerQueryService, + mockLcmEventsCmHandleStateHandler) def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']" diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy index 7a4bde07ac..b4e57c78b5 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy @@ -27,6 +27,8 @@ import org.onap.cps.ncmp.api.inventory.InventoryPersistence import spock.lang.Specification import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED +import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETING import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY import static org.onap.cps.ncmp.api.inventory.LockReasonCategory.LOCKED_MODULE_SYNC_FAILED @@ -39,11 +41,14 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification { def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, mockLcmEventsCreator, mockLcmEventsService) + def cmHandleId = 'cmhandle-id-1' + def compositeState + def yangModelCmHandle + def 'Update and Publish Events on State Change #stateChange'() { given: 'Cm Handle represented as YangModelCmHandle' - def cmHandleId = 'cmhandle-id-1' - def compositeState = new CompositeState(cmHandleState: fromCmHandleState) - def yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + compositeState = new CompositeState(cmHandleState: fromCmHandleState) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) when: 'update state is invoked' objectUnderTest.updateCmHandleState(yangModelCmHandle, toCmHandleState) then: 'state is saved using inventory persistence' @@ -62,9 +67,8 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification { def 'Update and Publish Events on State Change from NO_EXISTING state to ADVISED'() { given: 'Cm Handle represented as YangModelCmHandle in READY state' - def cmHandleId = 'cmhandle-id-1' - def compositeState = new CompositeState() - def yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + compositeState = new CompositeState() + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) when: 'update state is invoked' objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) then: 'state is saved using inventory persistence' @@ -75,10 +79,9 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification { def 'Update and Publish Events on State Change from LOCKED to ADVISED'() { given: 'Cm Handle represented as YangModelCmHandle in LOCKED state' - def cmHandleId = 'cmhandle-id-1' - def compositeState = new CompositeState(cmHandleState: LOCKED, + compositeState = new CompositeState(cmHandleState: LOCKED, lockReason: CompositeState.LockReason.builder().lockReasonCategory(LOCKED_MODULE_SYNC_FAILED).details('some lock details').build()) - def yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) when: 'update state is invoked' objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) then: 'state is saved using inventory persistence and old lock reason details are retained' @@ -93,9 +96,8 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification { def 'Update and Publish Events on State Change to READY with #scenario'() { given: 'Cm Handle represented as YangModelCmHandle' - def cmHandleId = 'cmhandle-id-1' - def compositeState = new CompositeState(cmHandleState: ADVISED) - def yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + compositeState = new CompositeState(cmHandleState: ADVISED) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) and: 'global sync flag is set' objectUnderTest.isGlobalDataSyncCacheEnabled = dataSyncCacheEnabled when: 'update cmhandle state is invoked' @@ -115,6 +117,31 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification { 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"' (){ + given: 'cm Handle as Yang model' + compositeState = new CompositeState(cmHandleState: READY) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + when: 'updating cm handle state to "DELETING"' + objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETING) + then: 'the cm handle state is as expected' + yangModelCmHandle.getCompositeState().getCmHandleState() == DELETING + and: 'method to persist cm handle state is called once' + 1 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()) + and: 'the method to publish Lcm event is called once' + 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) + } + def 'Update cmHandle state to "DELETED"' (){ + given: 'cm Handle with state "DELETING" as Yang model ' + compositeState = new CompositeState(cmHandleState: DELETING) + yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState) + when: 'updating cm handle state to "DELETED"' + objectUnderTest.updateCmHandleState(yangModelCmHandle, DELETED) + then: 'the cm handle state is as expected' + yangModelCmHandle.getCompositeState().getCmHandleState() == DELETED + and: 'the method to publish Lcm event is called once' + 1 * mockLcmEventsService.publishLcmEvent(cmHandleId, _) } } -- cgit 1.2.3-korg