package org.onap.cps.ncmp.api.impl
+import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
+import org.onap.cps.ncmp.api.models.UpgradedCmHandles
+
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
+import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
+
import com.fasterxml.jackson.databind.ObjectMapper
import com.hazelcast.map.IMap
import org.onap.cps.api.CpsDataService
import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
import org.onap.cps.ncmp.api.impl.exception.DmiRequestException
import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
+import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.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 spock.lang.Shared
import spock.lang.Specification
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_DOES_NOT_EXIST
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_ALREADY_EXIST
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_INVALID_ID
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.UNKNOWN_ERROR
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
-
class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
@Shared
def mockDmiDataOperations = Mock(DmiDataOperations)
def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler)
def mockInventoryPersistence = Mock(InventoryPersistence)
- def mockCmhandleQueries = Mock(CmHandleQueries)
+ def mockCmHandleQueries = Mock(CmHandleQueries)
def stubbedNetworkCmProxyCmHandlerQueryService = Stub(NetworkCmProxyCmHandleQueryService)
def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
def mockCpsDataService = Mock(CpsDataService)
def mockModuleSyncStartedOnCmHandles = Mock(IMap<String, Object>)
+ def trustLevelPerDmiPlugin = [:]
+ def mockTrustLevelManager = Mock(TrustLevelManager)
def objectUnderTest = getObjectUnderTest()
- def 'DMI Registration: Create, Update & Delete operations are processed in the right order'() {
- given: 'a registration with operations of all three types'
+ def 'DMI Registration: Create, Update, Delete & Upgrade operations are processed in the right order'() {
+ given: 'a registration with operations of all types'
def dmiRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
dmiRegistration.setCreatedCmHandles([new NcmpServiceCmHandle(cmHandleId: 'cmhandle-1', publicProperties: ['publicProp1': 'value'], dmiProperties: [:])])
dmiRegistration.setUpdatedCmHandles([new NcmpServiceCmHandle(cmHandleId: 'cmhandle-2', publicProperties: ['publicProp1': 'value'], dmiProperties: [:])])
dmiRegistration.setRemovedCmHandles(['cmhandle-2'])
+ dmiRegistration.setUpgradedCmHandles(new UpgradedCmHandles(cmHandles: ['cmhandle-3'], moduleSetTag: 'some-module-set-tag'))
and: 'cm handles are persisted'
mockInventoryPersistence.getYangModelCmHandles(['cmhandle-2']) >> [new YangModelCmHandle()]
+ and: 'cm handle is in READY state'
+ mockCmHandleQueries.cmHandleHasState('cmhandle-3', CmHandleState.READY) >> true
when: 'registration is processed'
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
then: 'cm-handles are removed first'
- 1 * objectUnderTest.parseAndRemoveCmHandlesInDmiRegistration(*_)
+ 1 * objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_)
and: 'de-registered cm handle entry is removed from in progress map'
1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
then: 'cm-handles are created'
- 1 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(*_)
+ 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_)
then: 'cm-handles are updated'
1 * mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_)
+ then: 'cm-handles are upgraded'
+ 1 * objectUnderTest.parseAndProcessUpgradedCmHandlesInRegistration(*_)
+ }
+
+ def 'DMI Registration upgrade operation with upgrade node state #scenario'() {
+ given: 'a registration with upgrade operation'
+ def dmiRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
+ dmiRegistration.setUpgradedCmHandles(new UpgradedCmHandles(cmHandles: ['cmhandle-3'], moduleSetTag: 'some-module-set-tag'))
+ and: 'exception while checking cm handle state'
+ mockCmHandleQueries.cmHandleHasState('cmhandle-3', CmHandleState.READY) >> isReady
+ when: 'registration is processed'
+ def result = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
+ then: 'upgrade operation contains expected error code'
+ assert result.upgradedCmHandles.status[0] == expectedResponseStatus
+ where: 'the following parameters are used'
+ scenario | isReady || expectedResponseStatus
+ 'READY' | true || Status.SUCCESS
+ 'Not READY' | false || Status.FAILURE
+ }
+
+ def 'DMI Registration upgrade with exception #scenario'() {
+ given: 'a registration with upgrade operation'
+ def dmiRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
+ dmiRegistration.setUpgradedCmHandles(new UpgradedCmHandles(cmHandles: ['cmhandle-3'], moduleSetTag: 'some-module-set-tag'))
+ and: 'exception while checking cm handle state'
+ mockCmHandleQueries.cmHandleHasState('cmhandle-3', CmHandleState.READY) >> { throw exception }
+ when: 'registration is processed'
+ def result = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
+ then: 'upgrade operation contains expected error code'
+ assert result.upgradedCmHandles.ncmpResponseStatus.code[0] == expectedErrorCode
+ where: 'the following parameters are used'
+ scenario | exception || expectedErrorCode
+ 'data node not found' | new DataNodeNotFoundException('some-dataspace-name', 'some-anchor-name') || '100'
+ 'cm handle is invalid' | new DataValidationException('some error message', 'some error details') || '110'
}
def 'DMI Registration: Response from all operations types are in response'() {
mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) >> updateResponses
and: 'create cm-handles can be processed successfully'
def createdResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-1')]
- objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(*_) >> createdResponses
+ objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_) >> createdResponses
and: 'delete cm-handles can be processed successfully'
def removeResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-3')]
- objectUnderTest.parseAndRemoveCmHandlesInDmiRegistration(*_) >> removeResponses
+ objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_) >> removeResponses
when: 'registration is processed'
def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
then: 'response has values from all operations'
when: 'update registration and sync module is called with correct DMI plugin information'
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'create cm handles registration and sync modules is called with the correct plugin information'
- 1 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+ 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)
+ and: 'dmi is added to the dmi trustLevel map'
+ assert trustLevelPerDmiPlugin.size() == 1
+ assert trustLevelPerDmiPlugin.containsKey(expectedDmiPluginRegisteredName)
where:
- scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin
- 'combined DMI plugin' | 'service1' | '' | ''
- 'data & model DMI plugins' | '' | 'service1' | 'service2'
- 'data & model using same service' | '' | 'service1' | 'service1'
+ scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedDmiPluginRegisteredName
+ 'combined DMI plugin' | 'service1' | '' | '' || 'service1'
+ 'data & model DMI plugins' | '' | 'service1' | 'service2' || 'service2'
+ 'data & model using same service' | '' | 'service1' | 'service1' || 'service1'
}
def 'Create CM-handle Validation: Invalid DMI plugin service name with #scenario'() {
def exceptionThrown = thrown(DmiRequestException.class)
assert exceptionThrown.getMessage().contains(expectedMessageDetails)
and: 'registration is not called'
- 0 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+ 0 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)
where:
scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedMessageDetails
'empty DMI plugins' | '' | '' | '' || 'No DMI plugin service names'
assert it.cmHandle == 'cmhandle'
}
and: 'state handler is invoked with the expected parameters'
- 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> {
+ 1 * mockLcmEventsCmHandleStateHandler.initiateStateAdvised(_) >> {
args ->
{
def cmHandleStatePerCmHandle = (args[0] as Map)
cmHandleStatePerCmHandle.each {
- assert (it.key.id == 'cmhandle'
- && it.key.dmiServiceName == 'my-server'
- && it.value == CmHandleState.ADVISED)
+ assert (it.id == 'cmhandle' && it.dmiServiceName == 'my-server')
}
}
}
'without dmi & public properties' | [:] | [:] || '[]' | '[]'
}
+ def 'Add CM-Handle to trustLevelPerCmHandle Successfully with: #scenario.'() {
+ given: 'a registration with trustLevel and populated cache'
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
+ dmiPluginRegistration.createdCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', registrationTrustLevel: TrustLevel.NONE),
+ new NcmpServiceCmHandle(cmHandleId: cmHandleId, registrationTrustLevel: registrationTrustLevel)]
+ when: 'registration is updated'
+ def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'a successful response is received'
+ assert response.createdCmHandles.size() == expectedNumberOfCreatedCmHandles
+ and: 'trustLevel is set for the created cm-handle'
+ 1 * mockTrustLevelManager.handleInitialRegistrationOfTrustLevels(_)
+ where:
+ scenario | cmHandleId | registrationTrustLevel || expectedNumberOfCreatedCmHandles
+ 'new trusted cm handle' | 'ch-new' | TrustLevel.COMPLETE || 2
+ 'existing cm handle without trust level' | 'ch-1' | null || 1
+ 'new cm handle without trust level' | 'ch-new' | null || 2
+ }
+
def 'Create CM-Handle Multiple Requests: All cm-handles creation requests are processed with some failures'() {
given: 'a registration with three cm-handles to be created'
def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server',
new NcmpServiceCmHandle(cmHandleId: 'cmhandle3')])
and: 'cm-handle creation is successful for 1st and 3rd; failed for 2nd'
def xpath = "somePathWithId[@id='cmhandle2']"
- mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(*_) >> { throw AlreadyDefinedException.forDataNodes([xpath], 'some-context') }
+ mockLcmEventsCmHandleStateHandler.initiateStateAdvised(*_) >> { throw AlreadyDefinedException.forDataNodes([xpath], 'some-context') }
when: 'registration is updated to create cm-handles'
def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'a response is received for all cm-handles'
response.createdCmHandles.each {
assert it.cmHandle == 'cmhandle2'
assert it.status == Status.FAILURE
- assert it.registrationError == CM_HANDLE_ALREADY_EXIST
+ assert it.ncmpResponseStatus == CM_HANDLE_ALREADY_EXIST
assert it.errorText == 'cm-handle already exists'
}
}
def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
dmiPluginRegistration.createdCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle')]
and: 'cm-handler registration fails: #scenario'
- mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(*_) >> { throw exception }
+ mockLcmEventsCmHandleStateHandler.initiateStateAdvised(*_) >> { throw exception }
when: 'registration is updated'
def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'a failure response is received'
with(response.createdCmHandles[0]) {
assert it.status == Status.FAILURE
assert it.cmHandle == 'cmhandle'
- assert it.registrationError == expectedError
+ assert it.ncmpResponseStatus == expectedError
assert it.errorText == expectedErrorText
}
where:
and: 'cm-handle updates can be processed successfully'
def updateOperationResponse = [CmHandleRegistrationResponse.createSuccessResponse('cm-handle-1'),
CmHandleRegistrationResponse.createFailureResponse('cm-handle-2', new Exception("Failed")),
- CmHandleRegistrationResponse.createFailureResponse('cm-handle-3', CM_HANDLE_DOES_NOT_EXIST),
+ CmHandleRegistrationResponse.createFailureResponse('cm-handle-3', CM_HANDLES_NOT_FOUND),
CmHandleRegistrationResponse.createFailureResponse('cm handle 4', CM_HANDLE_INVALID_ID)]
mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(_) >> updateOperationResponse
when: 'registration is updated'
and: '2nd cm-handle deletion fails'
with(response.removedCmHandles[1]) {
assert it.status == Status.FAILURE
- assert it.registrationError == UNKNOWN_ERROR
+ assert it.ncmpResponseStatus == UNKNOWN_ERROR
assert it.errorText == 'Failed'
assert it.cmHandle == 'cmhandle2'
}
assert it.status == Status.FAILURE
assert it.cmHandle == 'cmhandle'
assert it.errorText == 'Failed'
- assert it.registrationError == UNKNOWN_ERROR
+ assert it.ncmpResponseStatus == UNKNOWN_ERROR
}
}
with(response.removedCmHandles[0]) {
assert it.status == Status.FAILURE
assert it.cmHandle == 'cmhandle'
- assert it.registrationError == expectedError
+ assert it.ncmpResponseStatus == expectedError
assert it.errorText == expectedErrorText
}
and: 'the cm handle state is not updated to "DELETED"'
0 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_, CmHandleState.DELETED)
where:
- scenario | cmHandleId | deleteListElementException || expectedError | expectedErrorText
- 'cm-handle does not exist' | 'cmhandle' | new DataNodeNotFoundException('', '', '') || CM_HANDLE_DOES_NOT_EXIST | 'cm-handle does not exist'
- 'cm-handle has invalid name' | 'cm handle with space' | new DataValidationException('', '') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id'
- 'an unexpected exception' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed'
+ scenario | cmHandleId | deleteListElementException || expectedError | expectedErrorText
+ 'cm-handle does not exist' | 'cmhandle' | new DataNodeNotFoundException('', '', '') || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found'
+ 'cm-handle has invalid name' | 'cm handle with space' | new DataValidationException('', '') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id'
+ 'an unexpected exception' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed'
}
def getObjectUnderTest() {
return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations,
- mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmhandleQueries,
+ mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmHandleQueries,
stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService,
- mockModuleSyncStartedOnCmHandles))
+ mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager))
}
def addPersistedYangModelCmHandles(ids) {