diff options
11 files changed, 418 insertions, 53 deletions
@@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (C) 2021 Nordix Foundation. +# Copyright (C) 2021-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. @@ -52,11 +52,6 @@ committers: company: 'Ericsson Software Technology' id: 'toinesiebelink' timezone: 'Europe/Dublin' - - name: 'Bruno Sakoto' - email: 'bruno.sakoto@bell.ca' - company: 'Bell Canada' - id: 'brusak' - timezone: 'America/Toronto' - name: 'Aditya Puthuparambil' email: 'aditya.puthuparambil@bell.ca' company: 'Bell Canada' diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml index d16e977704..e0fb7ef153 100644 --- a/cps-application/src/main/resources/application.yml +++ b/cps-application/src/main/resources/application.yml @@ -164,3 +164,7 @@ timers: sleep-time-ms: 300000
cm-handle-data-sync:
sleep-time-ms: 30000
+
+data-sync:
+ cache:
+ enabled: false
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandler.java new file mode 100644 index 0000000000..7728b5f92d --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandler.java @@ -0,0 +1,39 @@ +/* + * ============LICENSE_START======================================================= + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.event; + +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.inventory.CmHandleState; + +/** + * The implementation of it should handle the persisting of composite state and delegate the request to publish the + * corresponding ncmp event. + */ +public interface NcmpEventsCmHandleStateHandler { + + /** + * Updates the composite state of cmHandle based on cmHandleState. + * + * @param yangModelCmHandle cm handle represented as yang model + * @param targetCmHandleState target cm handle state + */ + void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState); +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandlerImpl.java new file mode 100644 index 0000000000..26a1c5bab9 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandlerImpl.java @@ -0,0 +1,106 @@ +/* + * ============LICENSE_START======================================================= + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.event; + +import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED; +import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED; +import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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.CompositeStateUtils; +import org.onap.cps.ncmp.api.inventory.InventoryPersistence; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.cps.utils.JsonObjectMapper; +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class NcmpEventsCmHandleStateHandlerImpl implements NcmpEventsCmHandleStateHandler { + + private final InventoryPersistence inventoryPersistence; + private final NcmpEventsCreator ncmpEventsCreator; + private final JsonObjectMapper jsonObjectMapper; + private final NcmpEventsService ncmpEventsService; + + @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 { + updateToSpecifiedCmHandleState(yangModelCmHandle, targetCmHandleState); + publishNcmpEvent(yangModelCmHandle); + } + + } + + private void updateToSpecifiedCmHandleState(final YangModelCmHandle yangModelCmHandle, + final CmHandleState targetCmHandleState) { + + if (READY == targetCmHandleState) { + CompositeStateUtils.setCompositeStateToReadyWithInitialDataStoreSyncState(isGlobalDataSyncCacheEnabled) + .accept(yangModelCmHandle.getCompositeState()); + inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()); + } else if (ADVISED == targetCmHandleState) { + if (yangModelCmHandle.getCompositeState().getCmHandleState() == LOCKED) { + retryCmHandle(yangModelCmHandle); + } else { + registerNewCmHandle(yangModelCmHandle); + } + } else { + CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState()); + inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()); + } + + } + + private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) { + CompositeStateUtils.setCompositeStateForRetry() + .accept(yangModelCmHandle.getCompositeState()); + inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState()); + } + + private void registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) { + CompositeStateUtils.setCompositeState(ADVISED).accept(yangModelCmHandle.getCompositeState()); + inventoryPersistence.saveListElements( + String.format("{\"cm-handles\":[%s]}", jsonObjectMapper.asJsonString(yangModelCmHandle))); + } + + private void publishNcmpEvent(final YangModelCmHandle yangModelCmHandle) { + final NcmpServiceCmHandle ncmpServiceCmHandle = + YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle); + final String cmHandleId = ncmpServiceCmHandle.getCmHandleId(); + final NcmpEvent ncmpEvent = ncmpEventsCreator.populateNcmpEvent(cmHandleId, ncmpServiceCmHandle); + ncmpEventsService.publishNcmpEvent(cmHandleId, ncmpEvent); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java index 7b5ceb57a4..5e02e0d94f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java @@ -22,15 +22,12 @@ package org.onap.cps.ncmp.api.impl.event; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; -import org.onap.cps.ncmp.api.inventory.InventoryPersistence; -import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** - * NcmpEventService to map the event correctly and publish to the public topic. + * NcmpEventService to call the publisher and publish on the dedicated topic. */ @Slf4j @@ -38,12 +35,8 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class NcmpEventsService { - private final InventoryPersistence inventoryPersistence; - private final NcmpEventsPublisher ncmpEventsPublisher; - private final NcmpEventsCreator ncmpEventsCreator; - @Value("${app.ncmp.events.topic:ncmp-events}") private String topicName; @@ -54,13 +47,10 @@ public class NcmpEventsService { * Publish the NcmpEvent to the public topic. * * @param cmHandleId Cm Handle Id + * @param ncmpEvent Ncmp Event */ - public void publishNcmpEvent(final String cmHandleId) { + public void publishNcmpEvent(final String cmHandleId, final NcmpEvent ncmpEvent) { if (notificationsEnabled) { - final NcmpServiceCmHandle ncmpServiceCmHandle = - YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle( - inventoryPersistence.getYangModelCmHandle(cmHandleId)); - final NcmpEvent ncmpEvent = ncmpEventsCreator.populateNcmpEvent(cmHandleId, ncmpServiceCmHandle); ncmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent); } else { log.debug("Notifications disabled."); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateUtils.java new file mode 100644 index 0000000000..506bd11627 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateUtils.java @@ -0,0 +1,86 @@ +/* + * ============LICENSE_START======================================================= + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.inventory; + +import java.util.function.Consumer; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * It will have all the utility method responsible for handling the composite state. + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CompositeStateUtils { + + /** + * Sets the cmHandleState to the provided state and updates the timestamp. + * + * @return Updated CompositeState + */ + public static Consumer<CompositeState> setCompositeState(final CmHandleState cmHandleState) { + return compositeState -> { + compositeState.setCmHandleState(cmHandleState); + compositeState.setLastUpdateTimeNow(); + }; + } + + /** + * Sets the cmHandleState to READY and operational datastore sync state based on the global flag. + * + * @return Updated CompositeState + */ + public static Consumer<CompositeState> setCompositeStateToReadyWithInitialDataStoreSyncState( + final boolean isGlobalDataSyncCacheEnabled) { + return compositeState -> { + compositeState.setDataSyncEnabled(isGlobalDataSyncCacheEnabled); + compositeState.setCmHandleState(CmHandleState.READY); + final CompositeState.Operational operational = + getInitialDataStoreSyncState(compositeState.getDataSyncEnabled()); + final CompositeState.DataStores dataStores = + CompositeState.DataStores.builder().operationalDataStore(operational).build(); + compositeState.setDataStores(dataStores); + }; + } + + private static CompositeState.Operational getInitialDataStoreSyncState(final boolean dataSyncEnabled) { + final DataStoreSyncState dataStoreSyncState = + dataSyncEnabled ? DataStoreSyncState.UNSYNCHRONIZED : DataStoreSyncState.NONE_REQUESTED; + return CompositeState.Operational.builder().dataStoreSyncState(dataStoreSyncState).build(); + } + + /** + * Sets the cmHandleState to ADVISED and retain the lock details. Used in retry scenarios. + * + * @return Updated CompositeState + */ + public static Consumer<CompositeState> setCompositeStateForRetry() { + return 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); + }; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java index 0330991fd6..f18d843f81 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java @@ -31,6 +31,7 @@ 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; @@ -45,6 +46,9 @@ public class ModuleSyncWatchdog { private final ModuleSyncService moduleSyncService; + @Value("${data-sync.cache.enabled:false}") + private boolean isGlobalDataSyncCacheEnabled; + /** * Execute Cm Handle poll which changes the cm handle state from 'ADVISED' to 'READY'. */ @@ -96,11 +100,9 @@ public class ModuleSyncWatchdog { private Consumer<CompositeState> setCompositeStateToReadyWithInitialDataStoreSyncState() { return compositeState -> { + compositeState.setDataSyncEnabled(isGlobalDataSyncCacheEnabled); compositeState.setCmHandleState(CmHandleState.READY); - final CompositeState.Operational operational = CompositeState.Operational.builder() - .dataStoreSyncState(DataStoreSyncState.UNSYNCHRONIZED) - .lastSyncTime(CompositeState.nowInSyncTimeFormat()) - .build(); + final CompositeState.Operational operational = getDataStoreSyncState(compositeState.getDataSyncEnabled()); final CompositeState.DataStores dataStores = CompositeState.DataStores.builder() .operationalDataStore(operational) .build(); @@ -116,4 +118,11 @@ public class ModuleSyncWatchdog { .details(oldLockReasonDetails).build(); compositeState.setLockReason(lockReason); } + + private CompositeState.Operational getDataStoreSyncState(final boolean dataSyncEnabled) { + final DataStoreSyncState dataStoreSyncState = dataSyncEnabled + ? DataStoreSyncState.UNSYNCHRONIZED : DataStoreSyncState.NONE_REQUESTED; + return CompositeState.Operational.builder().dataStoreSyncState(dataStoreSyncState).build(); + } + } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandlerImplSpec.groovy new file mode 100644 index 0000000000..f2e730d3a3 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCmHandleStateHandlerImplSpec.groovy @@ -0,0 +1,122 @@ +/* + * ============LICENSE_START======================================================= + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.event + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +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.utils.JsonObjectMapper +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED +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 + +class NcmpEventsCmHandleStateHandlerImplSpec extends Specification { + + def mockInventoryPersistence = Mock(InventoryPersistence) + def mockNcmpEventsCreator = Mock(NcmpEventsCreator) + def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) + def mockNcmpEventsService = Mock(NcmpEventsService) + + def objectUnderTest = new NcmpEventsCmHandleStateHandlerImpl(mockInventoryPersistence, mockNcmpEventsCreator, spiedJsonObjectMapper, mockNcmpEventsService) + + 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) + when: 'update state is invoked' + objectUnderTest.updateCmHandleState(yangModelCmHandle, toCmHandleState) + then: 'state is saved using inventory persistence' + expectedCallsToInventoryPersistence * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) + and: 'event service is called to publish event' + expectedCallsToEventService * mockNcmpEventsService.publishNcmpEvent(cmHandleId, _) + where: 'state change parameters are provided' + stateChange | fromCmHandleState | toCmHandleState || expectedCallsToInventoryPersistence | expectedCallsToEventService + 'ADVISED to READY' | ADVISED | READY || 1 | 1 + 'READY to LOCKED' | READY | LOCKED || 1 | 1 + 'ADVISED to ADVISED' | ADVISED | ADVISED || 0 | 0 + 'READY to READY' | READY | READY || 0 | 0 + 'LOCKED to LOCKED' | LOCKED | LOCKED || 0 | 0 + + } + + 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) + when: 'update state is invoked' + objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED) + then: 'state is saved using inventory persistence' + 1 * mockInventoryPersistence.saveListElements(_) + and: 'event service is called to publish event' + 1 * mockNcmpEventsService.publishNcmpEvent(cmHandleId, _) + } + + 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, + lockReason: CompositeState.LockReason.builder().lockReasonCategory(LOCKED_MODULE_SYNC_FAILED).details('some lock details').build()) + def 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' + 1 * mockInventoryPersistence.saveCmHandleState(cmHandleId, _) >> { + args -> { + assert (args[1] as CompositeState).lockReason.details == 'some lock details' + } + } + and: 'event service is called to publish event' + 1 * mockNcmpEventsService.publishNcmpEvent(cmHandleId, _) + } + + 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) + and: 'global sync flag is set' + objectUnderTest.isGlobalDataSyncCacheEnabled = dataSyncCacheEnabled + 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-> { + assert (args[1] as CompositeState).dataSyncEnabled == dataSyncCacheEnabled + assert (args[1] as CompositeState).dataStores.operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState + + } + } + and: 'event service is called to publish event' + 1 * mockNcmpEventsService.publishNcmpEvent(cmHandleId, _) + where: + scenario | dataSyncCacheEnabled || expectedDataStoreSyncState + 'data sync cache enabled' | true || DataStoreSyncState.UNSYNCHRONIZED + 'data sync cache is not enabled' | false || DataStoreSyncState.NONE_REQUESTED + + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy index 52806a8673..8bf02c11c2 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy @@ -20,46 +20,30 @@ package org.onap.cps.ncmp.api.impl.event -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.InventoryPersistence + import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent import spock.lang.Specification class NcmpEventsServiceSpec extends Specification { - def mockInventoryPersistence = Mock(InventoryPersistence) def mockNcmpEventsPublisher = Mock(NcmpEventsPublisher) - def mockNcmpEventsCreator = Mock(NcmpEventsCreator) - def objectUnderTest = new NcmpEventsService(mockInventoryPersistence, mockNcmpEventsPublisher, mockNcmpEventsCreator) + def objectUnderTest = new NcmpEventsService(mockNcmpEventsPublisher) def 'Create and Publish ncmp event where events are #scenario'() { - given: 'a cm handle id and operation and responses are mocked' - mockResponses('test-cm-handle-id', 'test-topic') + given: 'a cm handle id and Ncmp Event' + def cmHandleId = 'test-cm-handle-id' + def ncmpEvent = new NcmpEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) and: 'notifications enabled is #notificationsEnabled' objectUnderTest.notificationsEnabled = notificationsEnabled when: 'service is called to publish ncmp event' - objectUnderTest.publishNcmpEvent('test-cm-handle-id') - then: 'creator is called #expectedTimesMethodCalled times' - expectedTimesMethodCalled * mockNcmpEventsCreator.populateNcmpEvent('test-cm-handle-id', _) - and: 'publisher is called #expectedTimesMethodCalled times' - expectedTimesMethodCalled * mockNcmpEventsPublisher.publishEvent(*_) + objectUnderTest.publishNcmpEvent('test-cm-handle-id', ncmpEvent) + then: 'publisher is called #expectedTimesMethodCalled times' + expectedTimesMethodCalled * mockNcmpEventsPublisher.publishEvent(_, cmHandleId, ncmpEvent) where: 'the following values are used' - scenario | notificationsEnabled|| expectedTimesMethodCalled - 'enabled' | true || 1 - 'disabled' | false || 0 - } - - def mockResponses(cmHandleId, topicName) { - - def yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, publicProperties: [new YangModelCmHandle.Property('publicProperty1', 'value1')], dmiProperties: []) - def ncmpEvent = new NcmpEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) - def ncmpServiceCmhandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle) - - mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle - mockNcmpEventsCreator.populateNcmpEvent(cmHandleId, ncmpServiceCmhandle) >> ncmpEvent - mockNcmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent) >> {} + scenario | notificationsEnabled || expectedTimesMethodCalled + 'enabled' | true || 1 + 'disabled' | false || 0 } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy index ad65763630..fa437987b5 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy @@ -23,6 +23,7 @@ package org.onap.cps.ncmp.api.inventory import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.model.DataNodeBuilder +import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder import spock.lang.Specification import java.time.OffsetDateTime @@ -63,4 +64,25 @@ class CompositeStateBuilderSpec extends Specification { assert compositeState.cmHandleState == CmHandleState.ADVISED } + def 'CompositeStateBuilder build'() { + given: 'A CompositeStateBuilder with all private fields set' + def finalCompositeStateBuilder = new CompositeStateBuilder() + .withCmHandleState(CmHandleState.ADVISED) + .withLastUpdatedTime(formattedDateAndTime.toString()) + .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, 'locked details') + .withOperationalDataStores(DataStoreSyncState.SYNCHRONIZED, formattedDateAndTime) + when: 'build is called' + def result = finalCompositeStateBuilder.build() + then: 'result is of the correct type' + assert result.class == CompositeState.class + and: 'built result should have correct values' + assert !result.getDataSyncEnabled() + assert result.getLastUpdateTime() == formattedDateAndTime + assert result.getLockReason().getLockReasonCategory() == LockReasonCategory.LOCKED_MODULE_SYNC_FAILED + assert result.getLockReason().getDetails() == 'locked details' + assert result.getCmHandleState() == CmHandleState.ADVISED + assert result.getDataStores().getOperationalDataStore().getDataStoreSyncState() == DataStoreSyncState.SYNCHRONIZED + assert result.getDataStores().getOperationalDataStore().getLastSyncTime() == formattedDateAndTime + } + } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy index 740a826075..4b92be37ab 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy @@ -24,6 +24,7 @@ package org.onap.cps.ncmp.api.inventory.sync 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.onap.cps.ncmp.api.inventory.CompositeStateBuilder @@ -41,12 +42,13 @@ class ModuleSyncWatchdogSpec extends Specification { def objectUnderTest = new ModuleSyncWatchdog(mockInventoryPersistence, mockSyncUtils, mockModuleSyncService) - def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles'() { - given: 'cm handles in an advised state' + def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles where #scenario'() { + 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.getAnAdvisedCmHandle() >>> [yangModelCmHandle1, yangModelCmHandle2, null] when: 'module sync poll is executed' @@ -57,8 +59,10 @@ 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) - and: 'the composite state cm handle state is now READY' + then: 'the composite state cm handle state is now READY' assert compositeState1.getCmHandleState() == CmHandleState.READY + and: 'the data store sync state returns the expected state' + compositeState1.getDataStores().operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState 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' @@ -69,6 +73,10 @@ 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'() { |