diff options
Diffstat (limited to 'cps-ncmp-service/src/test/groovy/org')
13 files changed, 283 insertions, 106 deletions
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy index 46c866282..c121ce076 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy @@ -20,7 +20,6 @@ package org.onap.cps.ncmp.api.impl -import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService import org.onap.cps.spi.CpsAdminPersistenceService import org.onap.cps.spi.CpsDataPersistenceService @@ -28,7 +27,6 @@ import org.onap.cps.spi.model.Anchor import org.onap.cps.spi.model.CmHandleQueryServiceParameters import org.onap.cps.spi.model.ConditionProperties import org.onap.cps.spi.model.DataNode -import org.onap.cps.utils.JsonObjectMapper import spock.lang.Specification import java.util.stream.Collectors @@ -39,8 +37,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { def cpsAdminPersistenceService = Mock(CpsAdminPersistenceService) NetworkCmProxyCmHandlerQueryService objectUnderTest = new NetworkCmProxyCmHandlerQueryServiceImpl( - cpsDataPersistenceService, cpsAdminPersistenceService, new JsonObjectMapper(new ObjectMapper()) - ) + cpsDataPersistenceService, cpsAdminPersistenceService) def 'Retrieve cm handles with public properties when #scenario.'() { given: 'a condition property' @@ -51,16 +48,19 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties]) and: 'mock services' mockResponses() - when: 'the service is invoked' - def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) - then: 'the correct expected cm handles are returned' - returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toSet()) == expectedCmHandleIds as Set + when: 'a query is execute (with and without Data)' + def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters) + def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + then: 'the correct expected cm handles ids are returned' + returnedCmHandlesJustIds == expectedCmHandleIds as Set + and: 'the correct cm handle data objects are returned' + returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == expectedCmHandleIds as Set where: 'the following data is used' - scenario | publicProperties || expectedCmHandleIds - 'single matching property' | [['Contact' : 'newemailforstore@bookstore.com']] || ['PNFDemo', 'PNFDemo2', 'PNFDemo4'] - 'public property dont match' | [['wont_match' : 'wont_match']] || [] - '2 properties, only one match (and)' | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': 'newemailforstore2@bookstore.com']] || ['PNFDemo4'] - '2 properties, no match (and)' | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': '']] || [] + scenario | publicProperties || expectedCmHandleIds + 'single property matches' | [['Contact' : 'newemailforstore@bookstore.com']] || ['PNFDemo1', 'PNFDemo2', 'PNFDemo4'] + 'public property does not match' | [['wont_match' : 'wont_match']] || [] + '2 properties, only one match' | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': 'newemailforstore2@bookstore.com']] || ['PNFDemo4'] + '2 properties, no matches' | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': '']] || [] } def 'Retrieve cm handles with module names when #scenario.'() { @@ -73,15 +73,17 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { and: 'mock services' mockResponses() when: 'the service is invoked' - def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters) + def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters) then: 'the correct expected cm handles are returned' - returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toSet()) == expectedCmHandleIds as Set + returnedCmHandlesJustIds == expectedCmHandleIds as Set + returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == expectedCmHandleIds as Set where: 'the following data is used' - scenario | moduleNames || expectedCmHandleIds - 'single matching module name' | [['moduleName' : 'MODULE-NAME-001']] || ['PNFDemo3', 'PNFDemo', 'PNFDemo2'] - 'module name dont match' | [['moduleName' : 'MODULE-NAME-004']] || [] - '2 module names, only one match (and)' | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-003']] || ['PNFDemo4'] - '2 module names, no match (and)' | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-004']] || [] + scenario | moduleNames || expectedCmHandleIds + 'single matching module name' | [['moduleName' : 'MODULE-NAME-001']] || ['PNFDemo3', 'PNFDemo1', 'PNFDemo2'] + 'module name dont match' | [['moduleName' : 'MODULE-NAME-004']] || [] + '2 module names, only one match' | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-003']] || ['PNFDemo4'] + '2 module names, no matches' | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-004']] || [] } def 'Retrieve cm handles with combined queries when #scenario.'() { @@ -97,12 +99,14 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { and: 'mock services' mockResponses() when: 'the service is invoked' - def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters) + def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters) then: 'the correct expected cm handles are returned' - returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toSet()) == expectedCmHandleIds as Set + returnedCmHandlesJustIds == expectedCmHandleIds as Set + returnedCmHandlesWithData.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == expectedCmHandleIds as Set where: 'the following data is used' scenario | moduleNames | publicProperties || expectedCmHandleIds - 'particularly intersect' | [['moduleName' : 'MODULE-NAME-001']] | [['Contact' : 'newemailforstore@bookstore.com']] || ['PNFDemo2', 'PNFDemo'] + 'particularly intersect' | [['moduleName' : 'MODULE-NAME-001']] | [['Contact' : 'newemailforstore@bookstore.com']] || ['PNFDemo1', 'PNFDemo2'] 'empty intersect' | [['moduleName' : 'MODULE-NAME-004']] | [['Contact' : 'newemailforstore@bookstore.com']] || [] 'total intersect' | [['moduleName' : 'MODULE-NAME-002']] | [['Contact2' : 'newemailforstore2@bookstore.com']] || ['PNFDemo4'] } @@ -112,38 +116,39 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { mockResponses() when: 'the service is invoked' def cmHandleQueryParameters = new CmHandleQueryServiceParameters() - def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters) + def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters) then: 'the correct expected cm handles are returned' - returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toSet()) == ['PNFDemo', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] as Set + returnedCmHandlesJustIds == ['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] as Set + returnedCmHandlesWithData.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == ['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] as Set } void mockResponses() { - def pNFDemo = new DataNode(xpath: 'cmHandle/id[\'PNFDemo\']', leaves: ['id':'PNFDemo']) - def pNFDemo2 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo2\']', leaves: ['id':'PNFDemo2']) - def pNFDemo3 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo3\']', leaves: ['id':'PNFDemo3']) - def pNFDemo4 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo4\']', leaves: ['id':'PNFDemo4']) + def pNFDemo1 = new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'PNFDemo1\']', leaves: ['id':'PNFDemo1']) + def pNFDemo2 = new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'PNFDemo2\']', leaves: ['id':'PNFDemo2']) + def pNFDemo3 = new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'PNFDemo3\']', leaves: ['id':'PNFDemo3']) + def pNFDemo4 = new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'PNFDemo4\']', leaves: ['id':'PNFDemo4']) + def dmiRegistry = new DataNode(xpath: '/dmi-registry', childDataNodes: [pNFDemo1, pNFDemo2, pNFDemo3, pNFDemo4]) + + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles', _) >> [pNFDemo1, pNFDemo2, pNFDemo4] + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'wont_match\' and @value=\'wont_match\']/ancestor::cm-handles', _) >> [] + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'newemailforstore2@bookstore.com\']/ancestor::cm-handles', _) >> [pNFDemo4] + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'\']/ancestor::cm-handles', _) >> [] + + cpsDataPersistenceService.getDataNode(_, _, '/dmi-registry', _) >> dmiRegistry - cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles', _) - >> [pNFDemo, pNFDemo2, pNFDemo4] - cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'wont_match\' and @value=\'wont_match\']/ancestor::cm-handles', _) - >> [] - cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'newemailforstore2@bookstore.com\']/ancestor::cm-handles', _) - >> [pNFDemo4] - cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'\']/ancestor::cm-handles', _) - >> [] - cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties/ancestor::cm-handles', _) - >> [pNFDemo, pNFDemo2, pNFDemo3, pNFDemo4] - cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo\']', _) >> [pNFDemo] - cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo2\']', _) >> [pNFDemo2] - cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo3\']', _) >> [pNFDemo3] - cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo4\']', _) >> [pNFDemo4] + cpsDataPersistenceService.getDataNode(_, _, '/dmi-registry/cm-handles[@id=\'PNFDemo1\']', _) >> pNFDemo1 + cpsDataPersistenceService.getDataNode(_, _, '/dmi-registry/cm-handles[@id=\'PNFDemo2\']', _) >> pNFDemo2 + cpsDataPersistenceService.getDataNode(_, _, '/dmi-registry/cm-handles[@id=\'PNFDemo3\']', _) >> pNFDemo3 + cpsDataPersistenceService.getDataNode(_, _, '/dmi-registry/cm-handles[@id=\'PNFDemo4\']', _) >> pNFDemo4 - cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-001']) >> [new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo3'), new Anchor(name: 'PNFDemo')] + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-001']) >> [new Anchor(name: 'PNFDemo1'), new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo3')] cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-004']) >> [] cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-003', 'MODULE-NAME-002']) >> [new Anchor(name: 'PNFDemo4')] cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002', 'MODULE-NAME-003']) >> [new Anchor(name: 'PNFDemo4')] cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-004', 'MODULE-NAME-002']) >> [] cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002', 'MODULE-NAME-004']) >> [] cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002']) >> [new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo4')] + cpsAdminPersistenceService.getAnchors(_) >> [new Anchor(name: 'PNFDemo1'), new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo3'), new Anchor(name: 'PNFDemo4')] } } 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 5357c42b7..02e6419c3 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 @@ -23,7 +23,6 @@ package org.onap.cps.ncmp.api.impl import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService -import org.onap.cps.api.CpsAdminService import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.exception.DmiRequestException @@ -32,7 +31,6 @@ import org.onap.cps.ncmp.api.inventory.InventoryPersistence import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse import org.onap.cps.ncmp.api.models.DmiPluginRegistration import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle -import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.DataNodeNotFoundException import org.onap.cps.spi.exceptions.DataValidationException @@ -59,11 +57,9 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def mockCpsDataService = Mock(CpsDataService) def mockCpsModuleService = Mock(CpsModuleService) def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) - def mockCpsAdminService = Mock(CpsAdminService) def mockDmiDataOperations = Mock(DmiDataOperations) def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler) def mockInventoryPersistence = Mock(InventoryPersistence) - def mockModuleSyncService = Mock(ModuleSyncService) def stubbedNetworkCmProxyCmHandlerQueryService = Stub(NetworkCmProxyCmHandlerQueryService) def noTimestamp = null def objectUnderTest = getObjectUnderTest() @@ -164,9 +160,14 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { } and: 'save list elements is invoked with the expected parameters' interaction { - def expectedJsonData = """{"cm-handles":[{"id":"cmhandle","dmi-service-name":"my-server","state":{"cm-handle-state":"ADVISED"},"additional-properties":$expectedDmiProperties,"public-properties":$expectedPublicProperties}]}""" 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry', - '/dmi-registry', expectedJsonData, noTimestamp) + '/dmi-registry', _, noTimestamp) >> { + args -> { + assert args[3].startsWith('{"cm-handles":[{"id":"cmhandle","dmi-service-name":"my-server","state":{"cm-handle-state":"ADVISED","last-update-time":"20') + assert args[3].contains(expectedDmiProperties) + assert args[3].contains(expectedPublicProperties) + } + } } where: scenario | dmiProperties | publicProperties || expectedDmiProperties | expectedPublicProperties @@ -347,7 +348,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def getObjectUnderTest() { return Spy(new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations, - mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, - mockModuleSyncService, stubbedNetworkCmProxyCmHandlerQueryService)) + mockCpsModuleService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, stubbedNetworkCmProxyCmHandlerQueryService)) } } 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 d58fe6a7c..2e333b507 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 @@ -27,16 +27,18 @@ 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.InventoryPersistence +import org.onap.cps.ncmp.api.inventory.LockReasonCategory +import org.onap.cps.ncmp.api.inventory.DataStoreSyncState 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.DataValidationException -import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService import org.onap.cps.spi.model.CmHandleQueryServiceParameters -import org.onap.cps.spi.model.ConditionProperties import spock.lang.Shared +import java.util.stream.Collectors + import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE @@ -44,7 +46,6 @@ import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum import org.onap.cps.utils.JsonObjectMapper import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.api.CpsAdminService import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations @@ -58,12 +59,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def mockCpsDataService = Mock(CpsDataService) def mockCpsModuleService = Mock(CpsModuleService) - def mockCpsAdminService = Mock(CpsAdminService) def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) def mockDmiDataOperations = Mock(DmiDataOperations) def nullNetworkCmProxyDataServicePropertyHandler = null def mockInventoryPersistence = Mock(InventoryPersistence) - def mockModuleSyncService = Mock(ModuleSyncService) def mockDmiPluginRegistration = Mock(DmiPluginRegistration) def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandlerQueryService) @@ -75,8 +74,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id') def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations, - mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, - mockModuleSyncService, mockCpsCmHandlerQueryService) + mockCpsModuleService, nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCpsCmHandlerQueryService) def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']" @@ -169,19 +167,29 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def 'Get a cm handle.'() { given: 'the system returns a yang modelled cm handle' def dmiServiceName = 'some service name' + def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, + lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MISBEHAVING).details("lock misbehaving details").build(), + lastUpdateTime: 'some-timestamp', + dataSyncEnabled: false, + dataStores: dataStores()) def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')] def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')] - def compositeState = new CompositeState(cmHandleState: 'ADVISED') def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState) 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle when: 'getting cm handle details for a given cm handle id from ncmp service' def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle') - then: 'the result returns the correct data' + then: 'the result is a ncmpServiceCmHandle' + result.class == NcmpServiceCmHandle.class + and: 'the cm handle contains the cm handle id' result.cmHandleId == 'some-cm-handle' + and: 'the cm handle contains the DMI Properties' result.dmiProperties ==[ Book:'Romance Novel' ] + and: 'the cm handle contains the public Properties' result.publicProperties == [ "Public Book":'Public Romance Novel' ] - result.compositeState.cmHandleState == CmHandleState.ADVISED + and: 'the cm handle contains the cm handle composite state' + result.compositeState == compositeState + } def 'Get a cm handle with an invalid id.'() { @@ -207,7 +215,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { } def 'Get cm handle public properties with an invalid id.'() { - when: 'getting cm handle details for a given cm handle id with an invalid name' + when: 'getting cm handle public properties for a given cm handle id with an invalid name' objectUnderTest.getCmHandlePublicProperties('invalid cm handle with spaces') then: 'an exception is thrown' thrown(DataValidationException) @@ -215,6 +223,33 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { 0 * mockInventoryPersistence.getYangModelCmHandle(*_) } + def 'Get cm handle composite state'() { + given: 'a yang modelled cm handle' + def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, + lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MISBEHAVING).details("lock misbehaving details").build(), + lastUpdateTime: 'some-timestamp', + dataSyncEnabled: false, + dataStores: dataStores()) + def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')] + def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')] + def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState) + and: 'the system returns this yang modelled cm handle' + 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle + when: 'getting cm handle composite state for a given cm handle id from ncmp service' + def result = objectUnderTest.getCmHandleCompositeState('some-cm-handle') + then: 'the result returns the correct data' + result == compositeState + } + + def 'Get cm handle composite state with an invalid id.'() { + when: 'getting cm handle composite state for a given cm handle id with an invalid name' + objectUnderTest.getCmHandleCompositeState('invalid cm handle with spaces') + then: 'an exception is thrown' + thrown(DataValidationException) + and: 'the yang model cm handle retriever is not invoked' + 0 * mockInventoryPersistence.getYangModelCmHandle(_) + } + def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() { given: 'cpsDataService returns valid datanode' mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', @@ -238,10 +273,11 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { when: 'parse and create cm handle in dmi registration then sync module' objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(mockDmiPluginRegistration) then: 'validate params for creating anchor and list elements' - 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry', - '/dmi-registry', '{"cm-handles":[{"id":"some-cm-handle-id",' + - '"state":{"cm-handle-state":"ADVISED"},' - + '"additional-properties":[],"public-properties":[]}]}', null) + 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, null) >> { + args -> { + assert args[3].startsWith('{"cm-handles":[{"id":"some-cm-handle-id","state":{"cm-handle-state":"ADVISED","last-update-time":"20') + } + } } def 'Execute cm handle id search'() { @@ -251,17 +287,45 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { conditionApiProperties.conditionName = 'hasAllModules' conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']] cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties] - and: 'valid CmHandleQueryParameters input' - def cmHandleQueryParameters = new CmHandleQueryServiceParameters() - def conditionProperties = new ConditionProperties() - conditionProperties.conditionName = 'hasAllModules' - conditionProperties.conditionParameters = [[moduleName: 'module-name-1']] - cmHandleQueryParameters.cmHandleQueryParameters = [conditionProperties] and: 'query cm handle method return with a data node list' - mockCpsCmHandlerQueryService.queryCmHandles(cmHandleQueryParameters) >> [new DataNode(leaves: [id: 'cm-handle-id-1'])] + mockCpsCmHandlerQueryService.queryCmHandleIds( + spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class)) + >> ['cm-handle-id-1'] when: 'execute cm handle search is called' def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters) then: 'result is the same collection as returned by the CPS Data Service' assert result == ['cm-handle-id-1'] as Set } + + def 'Getting module definitions.'() { + when: 'get module definitions method is called with a valid cm handle ID' + objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle') + then: 'CPS module services is invoked once' + 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() + def conditionApiProperties = new ConditionApiProperties() + conditionApiProperties.conditionName = 'hasAllModules' + conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']] + cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties] + and: 'query cm handle method return with a data node list' + mockCpsCmHandlerQueryService.queryCmHandles( + spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class)) + >> [new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')] + when: 'execute cm handle search is called' + def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters) + 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 + } } 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 e265fef05..52806a867 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 @@ -30,17 +30,25 @@ class NcmpEventsServiceSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) def mockNcmpEventsPublisher = Mock(NcmpEventsPublisher) - def mockNcmpEventsMapper = Mock(NcmpEventsCreator) + def mockNcmpEventsCreator = Mock(NcmpEventsCreator) - def objectUnderTest = new NcmpEventsService(mockInventoryPersistence, mockNcmpEventsPublisher, mockNcmpEventsMapper) + def objectUnderTest = new NcmpEventsService(mockInventoryPersistence, mockNcmpEventsPublisher, mockNcmpEventsCreator) - def 'Create and Publish event for #operation'() { + 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') + and: 'notifications enabled is #notificationsEnabled' + objectUnderTest.notificationsEnabled = notificationsEnabled when: 'service is called to publish ncmp event' objectUnderTest.publishNcmpEvent('test-cm-handle-id') - then: 'no exception is thrown' - noExceptionThrown() + then: 'creator is called #expectedTimesMethodCalled times' + expectedTimesMethodCalled * mockNcmpEventsCreator.populateNcmpEvent('test-cm-handle-id', _) + and: 'publisher is called #expectedTimesMethodCalled times' + expectedTimesMethodCalled * mockNcmpEventsPublisher.publishEvent(*_) + where: 'the following values are used' + scenario | notificationsEnabled|| expectedTimesMethodCalled + 'enabled' | true || 1 + 'disabled' | false || 0 } def mockResponses(cmHandleId, topicName) { @@ -50,9 +58,8 @@ class NcmpEventsServiceSpec extends Specification { def ncmpServiceCmhandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle) mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle - mockNcmpEventsMapper.populateNcmpEvent(cmHandleId, ncmpServiceCmhandle) >> ncmpEvent + mockNcmpEventsCreator.populateNcmpEvent(cmHandleId, ncmpServiceCmhandle) >> ncmpEvent mockNcmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent) >> {} } - } 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 60fec6f86..867094859 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 @@ -47,11 +47,11 @@ class CompositeStateBuilderSpec extends Specification { def "Composite State Specification"() { when: 'using composite state builder ' def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.ADVISED) - .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING,"").withOperationalDataStores(SyncState.UNSYNCHRONIZED, + .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING,"").withOperationalDataStores(DataStoreSyncState.UNSYNCHRONIZED, formattedDateAndTime.toString()).withLastUpdatedTime(formattedDateAndTime).build() then: 'it matches expected cm handle state and data store sync state' assert compositeState.cmHandleState == CmHandleState.ADVISED - assert compositeState.dataStores.operationalDataStore.syncState == SyncState.UNSYNCHRONIZED + assert compositeState.dataStores.operationalDataStore.dataStoreSyncState == DataStoreSyncState.UNSYNCHRONIZED } def "Build composite state from DataNode "() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy index 0a6f8c350..bf42fbfee 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy @@ -54,7 +54,7 @@ class CompositeStateSpec extends Specification { def dataStores() { DataStores.builder().operationalDataStore(Operational.builder() - .syncState(SyncState.NONE_REQUESTED) + .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED) .lastSyncTime(formattedDateAndTime.toString()).build()) .build() } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy index 8c23b302c..638af32e2 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy @@ -23,11 +23,13 @@ package org.onap.cps.ncmp.api.inventory import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.api.CpsDataService +import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.model.DataNode +import org.onap.cps.spi.model.ModuleDefinition import org.onap.cps.utils.JsonObjectMapper import spock.lang.Shared import spock.lang.Specification @@ -45,10 +47,11 @@ class InventoryPersistenceSpec extends Specification { def mockCpsDataService = Mock(CpsDataService) - def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService) + def mockCpsModuleService = Mock(CpsModuleService) + def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService) - def objectUnderTest = new InventoryPersistence(spiedJsonObjectMapper, mockCpsDataService, mockCpsDataPersistenceService) + def objectUnderTest = new InventoryPersistence(spiedJsonObjectMapper, mockCpsDataService, mockCpsModuleService, mockCpsDataPersistenceService) def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) @@ -178,7 +181,7 @@ class InventoryPersistenceSpec extends Specification { mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry', '//state/datastores/operational[@sync-state="'+'UNSYNCHRONIZED'+'"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> sampleDataNodes when: 'get cm handles by operational sync state as UNSYNCHRONIZED is invoked' - def result = objectUnderTest.getCmHandlesByOperationalSyncState(SyncState.UNSYNCHRONIZED) + def result = objectUnderTest.getCmHandlesByOperationalSyncState(DataStoreSyncState.UNSYNCHRONIZED) then: 'the returned result is a list of data nodes returned by cps data service' assert result == sampleDataNodes } @@ -189,12 +192,22 @@ class InventoryPersistenceSpec extends Specification { def cpsPath = '//cps-path' and: 'cps data service returns a valid data node' mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry', - cpsPath, OMIT_DESCENDANTS) + cpsPath, INCLUDE_ALL_DESCENDANTS) >> Arrays.asList(cmHandleDataNode) when: 'get cm handles by cps path is invoked' - def result = objectUnderTest.getCmHandleDataNodesByCpsPath(cpsPath) + def result = objectUnderTest.getCmHandleDataNodesByCpsPath(cpsPath, INCLUDE_ALL_DESCENDANTS) then: 'the returned result is a list of data nodes returned by cps data service' assert result.contains(cmHandleDataNode) } + def 'Get module definitions'() { + given: 'cps module service returns a collection of module definitions' + def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')] + mockCpsModuleService.getModuleDefinitionsByAnchorName('NFP-Operational','some-cmHandle-Id') >> moduleDefinitions + when: 'get module definitions by cmHandle is invoked' + def result = objectUnderTest.getModuleDefinitionsByCmHandleId('some-cmHandle-Id') + then: 'the returned result are the same module definitions as returned from the module service' + assert result == moduleDefinitions + } + } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/DataSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/DataSyncSpec.groovy index b062635db..20880ca3b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/DataSyncSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/DataSyncSpec.groovy @@ -25,7 +25,7 @@ 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.InventoryPersistence -import org.onap.cps.ncmp.api.inventory.SyncState +import org.onap.cps.ncmp.api.inventory.DataStoreSyncState import spock.lang.Specification class DataSyncSpec extends Specification { @@ -94,7 +94,7 @@ class DataSyncSpec extends Specification { def cmHandleState = CmHandleState.READY def compositeState = new CompositeState(cmHandleState: cmHandleState) compositeState.setDataStores(CompositeState.DataStores.builder() - .operationalDataStore(CompositeState.Operational.builder().syncState(SyncState.SYNCHRONIZED) + .operationalDataStore(CompositeState.Operational.builder().dataStoreSyncState(DataStoreSyncState.SYNCHRONIZED) .build()).build()) return compositeState } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy index 8050a571a..6a2fbe8e7 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy @@ -1,5 +1,5 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,10 @@ import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations 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.models.NcmpServiceCmHandle +import org.onap.cps.spi.CascadeDeleteAllowed +import org.onap.cps.spi.exceptions.SchemaSetNotFoundException import org.onap.cps.spi.model.ModuleReference import spock.lang.Specification @@ -45,7 +48,7 @@ class ModuleSyncServiceSpec extends Specification { def ncmpServiceCmHandle = new NcmpServiceCmHandle() def dmiServiceName = 'some service name' ncmpServiceCmHandle.cmHandleId = 'cmHandleId-1' - def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '' , '', CmHandleState.ADVISED, ncmpServiceCmHandle) + def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '', '', ncmpServiceCmHandle) and: 'DMI operations returns some module references' def moduleReferences = [ new ModuleReference(moduleName:'module1',revision:'1'), new ModuleReference(moduleName:'module2',revision:'2') ] @@ -68,6 +71,44 @@ class ModuleSyncServiceSpec extends Specification { 'no new module' | [['module1' : '1'], ['module2' : '2']] | [] | [:] | [new ModuleReference(moduleName:'module1',revision:'1'), new ModuleReference(moduleName:'module2',revision:'2')] } + def 'Delete Schema Set for CmHandle' () { + given: 'a CmHandle in the advised state' + def cmHandle = new YangModelCmHandle(id: 'some-cmhandle-id', compositeState: new CompositeState(cmHandleState: CmHandleState.ADVISED)) + and: 'the Schema Set exists for the CmHandle' + 1 * mockCpsModuleService.deleteSchemaSet(_ as String, 'some-cmhandle-id', + CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED) + when: 'delete schema set if exists is called' + objectUnderTest.deleteSchemaSetIfExists(cmHandle) + then: 'there are no exceptions' + noExceptionThrown() + } + + def 'Delete a non-existing Schema Set for CmHandle' () { + given: 'a CmHandle in the advised state' + def cmHandle = new YangModelCmHandle(id: 'some-cmhandle-id', compositeState: new CompositeState(cmHandleState: CmHandleState.ADVISED)) + and: 'the DB throws an exception because its Schema Set does not exist' + 1 * mockCpsModuleService.deleteSchemaSet(_ as String, 'some-cmhandle-id', + CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED) >> { throw new SchemaSetNotFoundException('some-dataspace-name', 'some-cmhandle-id') } + when: 'delete schema set if exists is called' + objectUnderTest.deleteSchemaSetIfExists(cmHandle) + then: 'there are no exceptions' + noExceptionThrown() + } + + def 'Delete Schema Set for CmHandle with other exception' () { + given: 'a CmHandle in the advised state' + def cmHandle = new YangModelCmHandle(id: 'some-cmhandle-id', compositeState: new CompositeState(cmHandleState: CmHandleState.ADVISED)) + and: 'an exception other than SchemaSetNotFoundException is thrown' + UnsupportedOperationException unsupportedOperationException = new UnsupportedOperationException(); + 1 * mockCpsModuleService.deleteSchemaSet(_ as String, 'some-cmhandle-id', + CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED) >> { throw unsupportedOperationException } + when: 'delete schema set if exists is called' + objectUnderTest.deleteSchemaSetIfExists(cmHandle) + then: 'an exception is thrown' + def result = thrown(UnsupportedOperationException) + result == unsupportedOperationException + } + def toModuleReference(moduleReferenceAsMap) { def moduleReferences = [].withDefault { [:] } moduleReferenceAsMap.forEach(property -> diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy index 614783efd..b7eb133bf 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy @@ -29,7 +29,7 @@ import org.onap.cps.ncmp.api.inventory.LockReasonCategory import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder import spock.lang.Specification -class ModuleSyncSpec extends Specification { +class ModuleSyncWatchdogSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) @@ -53,6 +53,8 @@ class ModuleSyncSpec extends Specification { objectUnderTest.executeAdvisedCmHandlePoll() then: 'the inventory persistence cm handle returns a composite state for the first cm handle' 1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState1 + and: 'module sync service deletes schema set of cm handle if it exists' + 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' @@ -90,16 +92,25 @@ class ModuleSyncSpec extends Specification { } - def 'Schedule a Cm-Handle Sync for LOCKED with reason LOCKED_MISBEHAVING Cm-Handles '() { + def 'Schedule a Cm-Handle Sync for LOCKED with reason LOCKED_MISBEHAVING Cm-Handles with #scenario'() { given: 'cm handles in an locked state' def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED) - .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, '').build() + .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, '').withLastUpdatedTimeNow().build() def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', compositeState: compositeState) and: 'sync utilities return a cm handle twice' mockSyncUtils.getLockedMisbehavingYangModelCmHandles() >> [yangModelCmHandle, yangModelCmHandle] + and: 'inventory persistence returns the composite state of the cm handle' + mockInventoryPersistence.getCmHandleState(yangModelCmHandle.getId()) >> compositeState + and: 'sync utils retry locked cm handle returns #isReadyForRetry' + mockSyncUtils.isReadyForRetry(compositeState) >>> isReadyForRetry when: 'module sync poll is executed' - objectUnderTest.executeLockedMisbehavingCmHandlePoll() + objectUnderTest.executeLockedCmHandlePoll() then: 'the first cm handle is updated to state "ADVISED" from "READY"' - 2 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.id, compositeState) + expectedNumberOfInvocationsToSaveCmHandleState * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.id, compositeState) + where: + scenario | isReadyForRetry || expectedNumberOfInvocationsToSaveCmHandleState + 'retry locked cm handle once' | [true, false] || 1 + 'retry locked cm handle twice' | [true, true] || 2 + 'do not retry locked cm handle' | [false, false] || 0 } } 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 14f201575..051172ca2 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 @@ -27,9 +27,11 @@ 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.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 import org.springframework.http.HttpStatus @@ -37,6 +39,9 @@ import org.springframework.http.ResponseEntity import spock.lang.Shared import spock.lang.Specification +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter + class SyncUtilsSpec extends Specification{ def mockInventoryPersistence = Mock(InventoryPersistence) @@ -48,6 +53,9 @@ class SyncUtilsSpec extends Specification{ def objectUnderTest = new SyncUtils(mockInventoryPersistence, 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']) def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() { @@ -83,7 +91,8 @@ class SyncUtilsSpec extends Specification{ def 'Get all locked Cm-Handle where Lock Reason is LOCKED_MISBEHAVING cm handle #scenario'() { given: 'the cps (persistence service) returns a collection of data nodes' mockInventoryPersistence.getCmHandleDataNodesByCpsPath( - '//lock-reason[@reason="LOCKED_MISBEHAVING"]/ancestor::cm-handles') >> [dataNode ] + '//lock-reason[@reason="LOCKED_MISBEHAVING"]/ancestor::cm-handles', + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode ] when: 'get locked Misbehaving cm handle is called' def result = objectUnderTest.getLockedMisbehavingYangModelCmHandles() then: 'the returned cm handle collection is the correct size' @@ -92,9 +101,24 @@ class SyncUtilsSpec extends Specification{ 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_MISBEHAVING, details) + .withLastUpdatedTime(lastUpdateTime).build()) + then: 'result returns #expectedResult' + result == expectedResult + where: + scenario | lastUpdateTime | details || expectedResult + 'is the first attempt' | '1900-01-01T00:00:00.000+0100' | 'First Attempt' || true + 'is greater than one minute' | '1900-01-01T00:00:00.000+0100' | 'Attempt #1 failed:' || true + 'is 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.getCmHandlesByOperationalSyncState(DataStoreSyncState.UNSYNCHRONIZED) >> unSynchronizedDataNodes mockInventoryPersistence.getCmHandlesByIdAndState("cm-handle-123", CmHandleState.READY) >> readyDataNodes when: 'get advised cm handle is called' objectUnderTest.getAnUnSynchronizedReadyCmHandle() diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy index 3376691ee..5903b1211 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy @@ -1,5 +1,5 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,9 @@ package org.onap.cps.ncmp.api.models import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.inventory.CmHandleState +import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder +import org.onap.cps.ncmp.api.inventory.LockReasonCategory +import org.onap.cps.ncmp.api.inventory.DataStoreSyncState import spock.lang.Specification import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA @@ -35,8 +38,15 @@ class YangModelCmHandleSpec extends Specification { ncmpServiceCmHandle.cmHandleId = 'cm-handle-id01' ncmpServiceCmHandle.dmiProperties = [myDmiProperty:'value1'] ncmpServiceCmHandle.publicProperties = [myPublicProperty:'value2'] + and: 'with a composite state' + def compositeState = new CompositeStateBuilder() + .withCmHandleState(CmHandleState.LOCKED) + .withLastUpdatedTime('some-update-time') + .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, 'locked other details') + .withOperationalDataStores(DataStoreSyncState.SYNCHRONIZED, 'some-sync-time').build() + ncmpServiceCmHandle.setCompositeState(compositeState) when: 'it is converted to a yang model cm handle' - def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('','','', CmHandleState.ADVISED, ncmpServiceCmHandle) + def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('', '', '', ncmpServiceCmHandle) then: 'the result has the right size' assert objectUnderTest.dmiProperties.size() == 1 and: 'the DMI property in the result has the correct name and value' @@ -45,11 +55,14 @@ class YangModelCmHandleSpec extends Specification { and: 'the public property in the result has the correct name and value' assert objectUnderTest.publicProperties[0].name == 'myPublicProperty' assert objectUnderTest.publicProperties[0].value == 'value2' + and: 'the composite state matches the composite state of the ncmpServiceCmHandle' + objectUnderTest.getCompositeState().cmHandleState == CmHandleState.LOCKED + objectUnderTest.getCompositeState() == ncmpServiceCmHandle.getCompositeState() } def 'Resolve DMI service name: #scenario and #requiredService service require.'() { given: 'a yang model cm handle' - def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, CmHandleState.ADVISED, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')) + def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')) expect: assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService where: diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy index b3ea3b870..2d993973e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy @@ -20,7 +20,6 @@ package org.onap.cps.ncmp.api.utils -import org.onap.cps.ncmp.api.inventory.CmHandleState import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING @@ -35,7 +34,7 @@ class DmiServiceUrlBuilderSpec extends Specification { @Shared YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName', - 'dmiDataServiceName', 'dmiModuleServiceName', CmHandleState.ADVISED , new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')) + 'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')) NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties() |