X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-ncmp-service%2Fsrc%2Ftest%2Fgroovy%2Forg%2Fonap%2Fcps%2Fncmp%2Fapi%2Finventory%2Fsync%2FSyncUtilsSpec.groovy;h=fb4ca3933d7030c27594a99211ff94d18abd283b;hb=a1a33160054bb9e7ffa57e18270dfa0f9a2ad77e;hp=2c45ab76952d70a77874e9ba0cd63229a2be8452;hpb=529f92c549a16ecd9ead36cc00d6f74f775ca638;p=cps.git diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy index 2c45ab769..fb4ca3933 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy @@ -1,5 +1,5 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ @@ -25,11 +25,13 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations import org.onap.cps.ncmp.api.impl.operations.DmiOperations +import org.onap.cps.ncmp.api.inventory.CmHandleQueries import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState +import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder +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.SyncState import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.DataNode import org.onap.cps.utils.JsonObjectMapper @@ -38,42 +40,63 @@ import org.springframework.http.ResponseEntity import spock.lang.Shared import spock.lang.Specification +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.util.stream.Collectors + class SyncUtilsSpec extends Specification{ def mockInventoryPersistence = Mock(InventoryPersistence) + def mockCmHandleQueries = Mock(CmHandleQueries) + def mockDmiDataOperations = Mock(DmiDataOperations) def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) - def objectUnderTest = new SyncUtils(mockInventoryPersistence, mockDmiDataOperations, jsonObjectMapper) + def objectUnderTest = new SyncUtils(mockInventoryPersistence, mockCmHandleQueries, mockDmiDataOperations, jsonObjectMapper) + + @Shared + def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(OffsetDateTime.now()) @Shared def dataNode = new DataNode(leaves: ['id': 'cm-handle-123']) + @Shared + def dataNodeAdditionalProperties = new DataNode(leaves: ['name': 'dmiProp1', 'value': 'dmiValue1']) + + def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() { given: 'the inventory persistence service returns a collection of data nodes' - mockInventoryPersistence.getCmHandlesByState(CmHandleState.ADVISED) >> dataNodeCollection - when: 'get advised cm handle is called' - objectUnderTest.getAnAdvisedCmHandle() + mockCmHandleQueries.getCmHandlesByState(CmHandleState.ADVISED) >> dataNodeCollection + and: 'we have some additional (dmi, private) properties' + dataNodeAdditionalProperties.xpath = dataNode.xpath + '/additional-properties[@name="dmiProp1"]' + dataNode.childDataNodes = [dataNodeAdditionalProperties] + when: 'get advised cm handles are fetched' + def yangModelCmHandles = objectUnderTest.getAdvisedCmHandles() then: 'the returned data node collection is the correct size' - dataNodeCollection.size() == expectedDataNodeSize - and: 'get yang model cm handles is invoked the correct number of times' - expectedCallsToGetYangModelCmHandle * mockInventoryPersistence.getYangModelCmHandle('cm-handle-123') + yangModelCmHandles.size() == expectedDataNodeSize + and: 'if there is a data node the additional (dmi, private) properties are included' + if (expectedDataNodeSize > 0) { + assert yangModelCmHandles[0].dmiProperties[0].name == 'dmiProp1' + assert yangModelCmHandles[0].dmiProperties[0].value == 'dmiValue1' + } + and: 'yang model collection contains the correct data' + yangModelCmHandles.stream().map(yangModel -> yangModel.id).collect(Collectors.toSet()) == + dataNodeCollection.stream().map(dataNode -> dataNode.leaves.get("id")).collect(Collectors.toSet()) where: 'the following scenarios are used' scenario | dataNodeCollection || expectedCallsToGetYangModelCmHandle | expectedDataNodeSize - 'exists' | [ dataNode ] || 1 | 1 - 'does not exist' | [ ] || 0 | 0 - + 'exists' | [dataNode] || 1 | 1 + 'does not exist' | [] || 0 | 0 } def 'Update Lock Reason, Details and Attempts where lock reason #scenario'() { given: 'A locked state' - def compositeState = new CompositeState(lockReason: lockReason) + def compositeState = new CompositeState(lockReason: lockReason) when: 'update cm handle details and attempts is called' - objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.LOCKED_MISBEHAVING, 'new error message') + objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, 'new error message') then: 'the composite state lock reason and details are updated' - assert compositeState.lockReason.lockReasonCategory == LockReasonCategory.LOCKED_MISBEHAVING + assert compositeState.lockReason.lockReasonCategory == LockReasonCategory.LOCKED_MODULE_SYNC_FAILED assert compositeState.lockReason.details == expectedDetails where: scenario | lockReason || expectedDetails @@ -81,24 +104,39 @@ class SyncUtilsSpec extends Specification{ 'exists' | CompositeState.LockReason.builder().details("Attempt #2 failed: some error message").build() || 'Attempt #3 failed: new error message' } - def 'Get all locked Cm-Handle where Lock Reason is LOCKED_MISBEHAVING cm handle #scenario'() { + def 'Get all locked Cm-Handle where Lock Reason is LOCKED_MODULE_SYNC_FAILED cm handle #scenario'() { given: 'the cps (persistence service) returns a collection of data nodes' - mockInventoryPersistence.getCmHandleDataNodesByCpsPath( - '//lock-reason[@reason="LOCKED_MISBEHAVING"]/ancestor::cm-handles', - FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode ] + mockCmHandleQueries.getCmHandleDataNodesByCpsPath( + '//lock-reason[@reason="LOCKED_MODULE_SYNC_FAILED"]', + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode] when: 'get locked Misbehaving cm handle is called' - def result = objectUnderTest.getLockedMisbehavingYangModelCmHandles() + def result = objectUnderTest.getModuleSyncFailedCmHandles() then: 'the returned cm handle collection is the correct size' result.size() == 1 and: 'the correct cm handle is returned' result[0].id == 'cm-handle-123' } + def 'Retry Locked Cm-Handle where the last update time is #scenario'() { + when: 'retry locked cm handle is invoked' + def result = objectUnderTest.isReadyForRetry(new CompositeStateBuilder() + .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, details) + .withLastUpdatedTime(lastUpdateTime).build()) + then: 'result returns #expectedResult' + result == expectedResult + where: + scenario | lastUpdateTime | details || expectedResult + 'the first attempt' | '1900-01-01T00:00:00.000+0100' | 'First Attempt' || true + 'greater than one minute' | '1900-01-01T00:00:00.000+0100' | 'Attempt #1 failed:' || true + 'less than eight minutes' | formattedDateAndTime | 'Attempt #3 failed:' || false + } + + def 'Get a Cm-Handle where Operational Sync state is UnSynchronized and Cm-handle state is READY and #scenario'() { given: 'the inventory persistence service returns a collection of data nodes' - mockInventoryPersistence.getCmHandlesByOperationalSyncState(SyncState.UNSYNCHRONIZED) >> unSynchronizedDataNodes - mockInventoryPersistence.getCmHandlesByIdAndState("cm-handle-123", CmHandleState.READY) >> readyDataNodes - when: 'get advised cm handle is called' + mockCmHandleQueries.getCmHandlesByOperationalSyncState(DataStoreSyncState.UNSYNCHRONIZED) >> unSynchronizedDataNodes + mockCmHandleQueries.getCmHandlesByIdAndState("cm-handle-123", CmHandleState.READY) >> readyDataNodes + when: 'get advised cm handles are fetched' objectUnderTest.getAnUnSynchronizedReadyCmHandle() then: 'the returned data node collection is the correct size' readyDataNodes.size() == expectedDataNodeSize