Allow separate registration of DMIDataPlugin and DmiModelPugin
Moved relevant code from NetworkCmProxyDataServiceImp to DmiOperations
Split DmiOperations into DMiData... and DMIModelOperations
Merged update-operation changes
Added tests for error message validation in NetworkCmProxyDataServiceImplSpec
Removede @Service from DMIOperations and added @component to
DmiDataOperations & DmiModelOperations
Verify sync robot test is now hardened
Added exitonfailure so robot tests stop after first encountered failed
test
Issue-ID: CPS-736
Change-Id: I0b40931cc8cd4fc0452328a0a7e0f60e6fc38d0a
Signed-off-by: JosephKeenan <joseph.keenan@est.tech>
Signed-off-by: ToineSiebelink <toine.siebelink@est.tech>
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy
new file mode 100644
index 0000000..2a85a4a
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy
@@ -0,0 +1,74 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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
+
+
+import org.onap.cps.api.CpsAdminService
+import org.onap.cps.api.CpsModuleService
+import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle
+import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.spi.model.ModuleReference
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import spock.lang.Specification
+
+class NetworkCmProxyDataServiceImplModelSyncSpec extends Specification {
+
+ def mockCpsModuleService = Mock(CpsModuleService)
+ def mockCpsAdminService = Mock(CpsAdminService)
+ def mockDmiModelOperations = Mock(DmiModelOperations)
+
+ def objectUnderTest = new NetworkCmProxyDataServiceImpl(null, mockDmiModelOperations,
+ mockCpsModuleService, null, null, mockCpsAdminService, null)
+
+ def expectedDataspaceName = 'NFP-Operational'
+
+ def 'Sync model for a (new) cm handle with #scenario'() {
+ given: 'persistence cm handle is given'
+ def cmHandleForModelSync = new PersistenceCmHandle(id:'some cm handle', dmiServiceName: 'some service name')
+ and: 'additional properties are set as required'
+ if (additionalProperties!=null) {
+ cmHandleForModelSync.asAdditionalProperties(additionalProperties)
+ }
+ and: 'dmi operations returns some module references'
+ def jsonData = TestUtils.getResourceFileContent('cmHandleModules.json')
+ def moduleReferencesFromCmHandleAsJson = new ResponseEntity<String>(jsonData, HttpStatus.OK)
+ mockDmiModelOperations.getModuleReferences(cmHandleForModelSync) >> moduleReferencesFromCmHandleAsJson
+ and: 'CPS-Core returns list of existing module resources'
+ mockCpsModuleService.getYangResourceModuleReferences(expectedDataspaceName) >> existingModuleResourcesInCps
+ and: 'DMI-Plugin returns resource(s) for "new" module(s)'
+ def moduleResources = new ResponseEntity<String>(sdncReponseBody, HttpStatus.OK)
+ mockDmiModelOperations.getNewYangResourcesFromDmi(cmHandleForModelSync, [new ModuleReference('module1', '1')]) >> moduleResources
+ when: 'module sync is triggered'
+ objectUnderTest.syncModulesAndCreateAnchor(cmHandleForModelSync)
+ then: 'the CPS module service is called once with the correct parameters'
+ 1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), expectedYangResourceToContentMap, expectedKnownModules)
+ and: 'admin service create anchor method has been called with correct parameters'
+ 1 * mockCpsAdminService.createAnchor(expectedDataspaceName, cmHandleForModelSync.getId(), cmHandleForModelSync.getId())
+ where: 'the following parameters are used'
+ scenario | additionalProperties | existingModuleResourcesInCps | sdncReponseBody || expectedYangResourceToContentMap | expectedKnownModules | expectedJsonForAdditionalProperties
+ 'one unknown module' | ['name1': 'value1'] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] | '{"name1":"value1"}'
+ 'no add. properties' | [:] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] | '{}'
+ 'additional properties is null' | null | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] | '{}'
+ 'no unknown module' | [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '[]' || [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '{}'
+ }
+}
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
new file mode 100644
index 0000000..86c01b4
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -0,0 +1,167 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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
+
+import com.fasterxml.jackson.core.JsonProcessingException
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.ncmp.api.impl.exception.NcmpException
+import org.onap.cps.ncmp.api.models.CmHandle
+import org.onap.cps.ncmp.api.models.DmiPluginRegistration
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException
+import org.onap.cps.spi.exceptions.DataValidationException
+import spock.lang.Shared
+import spock.lang.Specification
+
+class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
+
+ @Shared
+ def persistenceCmHandle = new CmHandle()
+
+ @Shared
+ def cmHandlesArray = ['cmHandle001']
+
+ def mockCpsDataService = Mock(CpsDataService)
+ def spyObjectMapper = Spy(ObjectMapper)
+
+ def noTimestamp = null
+
+ def 'Register or re-register a DMI Plugin for the given cm-handle(s) with #scenario process.'() {
+ given: 'a registration'
+ def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'my-server')
+ persistenceCmHandle.cmHandleID = '123'
+ persistenceCmHandle.cmHandleProperties = [name1: 'value1', name2: 'value2']
+ dmiPluginRegistration.createdCmHandles = createdCmHandles
+ dmiPluginRegistration.updatedCmHandles = updatedCmHandles
+ dmiPluginRegistration.removedCmHandles = removedCmHandles
+ def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,"additional-properties":[{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]}]}'
+ when: 'registration is updated and modules are synced'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'save list elements is invoked with the expected parameters'
+ expectedCallsToSaveNode * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
+ '/dmi-registry', expectedJsonData, noTimestamp)
+ and: 'update node and child data nodes is invoked with correct parameters'
+ expectedCallsToUpdateNode * mockCpsDataService.updateNodeLeavesAndExistingDescendantLeaves('NCMP-Admin',
+ 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, noTimestamp)
+ and : 'delete list or list element is invoked with the correct parameters'
+ expectedCallsToDeleteListElement * mockCpsDataService.deleteListOrListElement('NCMP-Admin',
+ 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp)
+ where:
+ scenario | createdCmHandles | updatedCmHandles | removedCmHandles || expectedCallsToSaveNode | expectedCallsToUpdateNode | expectedCallsToDeleteListElement
+ 'create' | [persistenceCmHandle] | [] | [] || 1 | 0 | 0
+ 'update' | [] | [persistenceCmHandle] | [] || 0 | 1 | 0
+ 'delete' | [] | [] | cmHandlesArray || 0 | 0 | 1
+ 'create, update and delete' | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray || 1 | 1 | 1
+ 'no valid data' | null | null | null || 0 | 0 | 0
+ }
+
+ def 'Register a DMI Plugin for the given cm-handle(s) without additional properties.'() {
+ given: 'a registration without cm-handle properties'
+ NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'my-server')
+ persistenceCmHandle.cmHandleID = '123'
+ persistenceCmHandle.cmHandleProperties = null
+ dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
+ def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,"additional-properties":[]}]}'
+ when: 'registration is updated'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'save list elements is invoked with the expected parameters'
+ 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
+ '/dmi-registry', expectedJsonData, noTimestamp)
+ }
+
+ def 'Register a DMI Plugin for a given cm-handle(s) with JSON processing errors during #scenario process.'() {
+ given: 'a registration without cm-handle properties '
+ NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'some-plugin')
+ dmiPluginRegistration.createdCmHandles = createdCmHandles
+ dmiPluginRegistration.updatedCmHandles = updatedCmHandles
+ and: 'an json processing exception occurs'
+ spyObjectMapper.writeValueAsString(_) >> { throw (new JsonProcessingException('')) }
+ when: 'registration is updated and modules are synced'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'a data validation exception is thrown'
+ thrown(DataValidationException)
+ where:
+ scenario | createdCmHandles | updatedCmHandles
+ 'create' | [persistenceCmHandle] | []
+ 'update' | [] | [persistenceCmHandle]
+ }
+
+ def 'Register a DMI Plugin for the given cm-handle(s) with no data found during delete process.'() {
+ given: 'a registration without cm-handle properties '
+ NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'some-plugin')
+ dmiPluginRegistration.removedCmHandles = ['some cm handle']
+ and: 'an json processing exception occurs during delete process'
+ mockCpsDataService.deleteListOrListElement(*_) >> { throw (new DataNodeNotFoundException('','')) }
+ when: 'registration is updated and modules are synced'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'no exception is thrown'
+ noExceptionThrown()
+ }
+
+ def 'Dmi plugin registration with #scenario'() {
+ given: 'a registration '
+ def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:dmiPlugin, dmiModelPlugin:dmiModelPlugin,
+ dmiDataPlugin:dmiDataPlugin)
+ dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
+ 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)
+ where:
+ scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin
+ 'combined DMI plugin' | 'service1' | '' | ''
+ 'data & model DMI plugins' | '' | 'service1' | 'service2'
+ 'data & model using same service' | '' | 'service1' | 'service1'
+ }
+
+ def 'Invalid dmi plugin registration with #scenario'() {
+ given: 'a registration '
+ def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:dmiPlugin, dmiModelPlugin:dmiModelPlugin,
+ dmiDataPlugin:dmiDataPlugin)
+ dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
+ when: 'registration is called with incorrect DMI plugin information'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'an NcmpException is thrown with correct message details'
+ def exceptionThrown = thrown(NcmpException)
+ assert exceptionThrown.getMessage().contains(expectedMessageDetails)
+ and: 'registration is not called'
+ 0 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+ where:
+ scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedMessageDetails
+ 'no DMI plugin' | '' | '' | '' || 'No DMI plugin service names'
+ 'all DMI plugins' | 'service1' | 'service2' | 'service3' || 'Invalid combination of plugin service names'
+ 'no model DMI plugin' | 'service1' | '' | 'service2' || 'Invalid combination of plugin service names'
+ 'no data DMI plugin' | 'service1' | 'service2' | '' || 'Invalid combination of plugin service names'
+ }
+
+ def getObjectUnderTestWithModelSyncDisabled() {
+ def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(null, null, null,
+ mockCpsDataService, null, null, spyObjectMapper))
+ objectUnderTest.syncModulesAndCreateAnchor(*_) >> null
+ return objectUnderTest
+ }
+}
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 b0c447e..8bb0ee2 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
@@ -22,79 +22,54 @@
package org.onap.cps.ncmp.api.impl
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient
+import org.onap.cps.ncmp.api.impl.operations.DmiRequestBody
+import org.springframework.http.HttpHeaders
+
+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
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE
+
import com.fasterxml.jackson.core.JsonProcessingException
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.api.CpsQueryService
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
import org.onap.cps.ncmp.api.impl.exception.NcmpException
-import org.onap.cps.ncmp.api.impl.operation.DmiOperations
-import org.onap.cps.ncmp.api.models.CmHandle
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.PersistenceCmHandle
-import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
+import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
import org.onap.cps.spi.FetchDescendantsOption
-import org.onap.cps.spi.exceptions.DataNodeNotFoundException
-import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.DataNode
-import org.onap.cps.spi.model.ModuleReference
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
-import spock.lang.Shared
import spock.lang.Specification
class NetworkCmProxyDataServiceImplSpec extends Specification {
- @Shared
- def persistenceCmHandle = new CmHandle()
- @Shared
- def cmHandlesArray = ['cmHandle001']
-
def mockCpsDataService = Mock(CpsDataService)
def mockCpsQueryService = Mock(CpsQueryService)
- def mockDmiOperations = Mock(DmiOperations)
def mockCpsModuleService = Mock(CpsModuleService)
def mockCpsAdminService = Mock(CpsAdminService)
- def mockDmiProperties = Mock(NcmpConfiguration.DmiProperties)
def spyObjectMapper = Spy(ObjectMapper)
+ def mockDmiDataOperations = Mock(DmiDataOperations)
- def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
- mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper)
+ def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiDataOperations, null,
+ mockCpsModuleService, mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper)
def cmHandle = 'some handle'
def noTimestamp = null
def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
def expectedDataspaceName = 'NFP-Operational'
-
- def 'Get data node.'() {
- when: 'queryDataNodes is invoked'
- objectUnderTest.getDataNode(cmHandle, 'some xpath', fetchDescendantsOption)
- then: 'the persistence data service is called once with the correct parameters'
- 1 * mockCpsDataService.getDataNode(expectedDataspaceName, cmHandle, 'some xpath', fetchDescendantsOption)
- where: 'all fetch descendants options are supported'
- fetchDescendantsOption << FetchDescendantsOption.values()
- }
-
- def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
- given: 'a cm Handle and a cps path'
- def cpsPath = '/cps-path'
- when: 'queryDataNodes is invoked'
- objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
- then: 'the persistence query service is called once with the correct parameters'
- 1 * mockCpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
- where: 'all fetch descendants options are supported'
- fetchDescendantsOption << FetchDescendantsOption.values()
- }
-
def 'Create full data node: #scenario.'() {
- given: 'a cm handle and root xpath'
+ given: 'json data'
def jsonData = 'some json'
when: 'createDataNode is invoked'
objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
- then: 'the CPS service method is invoked once with the expected parameters'
+ then: 'save data is invoked once with the expected parameters'
1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, jsonData, noTimestamp)
where: 'following parameters were used'
scenario | xpath
@@ -103,274 +78,38 @@
}
def 'Create child data node.'() {
- given: 'a cm handle and parent node xpath'
+ given: 'json data and xpath'
def jsonData = 'some json'
def xpath = '/test-node'
- when: 'createDataNode is invoked'
+ when: 'create data node is invoked'
objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
- then: 'the CPS service method is invoked once with the expected parameters'
+ then: 'save data is invoked once with the expected parameters'
1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
}
def 'Add list-node elements.'() {
- given: 'a cm handle and parent node xpath'
+ given: 'json data and xpath'
def jsonData = 'some json'
def xpath = '/test-node'
- when: 'addListNodeElements is invoked'
+ when: 'add list node element is invoked'
objectUnderTest.addListNodeElements(cmHandle, xpath, jsonData)
- then: 'the CPS service method is invoked once with the expected parameters'
+ then: 'the save list elements is invoked once with the expected parameters'
1 * mockCpsDataService.saveListElements(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
}
- def 'Update data node leaves.'() {
- given: 'a cm Handle and a cps path'
- def xpath = '/xpath'
- def jsonData = 'some json'
- when: 'updateNodeLeaves is invoked'
- objectUnderTest.updateNodeLeaves(cmHandle, xpath, jsonData)
- then: 'the persistence service is called once with the correct parameters'
- 1 * mockCpsDataService.updateNodeLeaves(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
- }
-
- def 'Replace data node tree.'() {
- given: 'a cm Handle and a cps path'
- def xpath = '/xpath'
- def jsonData = 'some json'
- when: 'replaceNodeTree is invoked'
- objectUnderTest.replaceNodeTree(cmHandle, xpath, jsonData)
- then: 'the persistence service is called once with the correct parameters'
- 1 * mockCpsDataService.replaceNodeTree(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
- }
-
- def 'Register or re-register a DMI Plugin with #scenario cm handles.'() {
- given: 'a registration '
- def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.dmiPlugin = 'my-server'
- persistenceCmHandle.cmHandleID = '123'
- persistenceCmHandle.cmHandleProperties = [name1: 'value1', name2: 'value2']
- dmiPluginRegistration.createdCmHandles = createdCmHandles
- dmiPluginRegistration.updatedCmHandles = updatedCmHandles
- dmiPluginRegistration.removedCmHandles = removedCmHandles
- def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]}]}'
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'cps save list elements is invoked with the expected parameters'
- expectedCallsToSaveNode * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
- '/dmi-registry', expectedJsonData, noTimestamp)
- and: 'update node and child data nodes is invoked with correct parameters'
- expectedCallsToUpdateNode * mockCpsDataService.updateNodeLeavesAndExistingDescendantLeaves('NCMP-Admin',
- 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, noTimestamp)
- and : 'delete list or list element is invoked with the correct parameters'
- expectedCallsToDeleteListElement * mockCpsDataService.deleteListOrListElement('NCMP-Admin',
- 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp)
-
- where:
- scenario | createdCmHandles | updatedCmHandles | removedCmHandles || expectedCallsToSaveNode | expectedCallsToUpdateNode | expectedCallsToDeleteListElement
- 'create' | [persistenceCmHandle] | [] | [] || 1 | 0 | 0
- 'update' | [] | [persistenceCmHandle] | [] || 0 | 1 | 0
- 'delete' | [] | [] | cmHandlesArray || 0 | 0 | 1
- 'create, update and delete' | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray || 1 | 1 | 1
- 'no valid data' | null | null | null || 0 | 0 | 0
- }
-
- def 'Register a DMI Plugin for the given cmHandle without additional properties.'() {
- given: 'a registration without cmHandle properties '
- NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.dmiPlugin = 'my-server'
- persistenceCmHandle.cmHandleID = '123'
- persistenceCmHandle.cmHandleProperties = null
- dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
- def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[]}]}'
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'the cps save list element is invoked with the expected parameters'
- 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
- '/dmi-registry', expectedJsonData, noTimestamp)
- }
-
- def 'Register a DMI Plugin with JSON processing errors during #scenario.'() {
- given: 'a registration without cmHandle properties '
- NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.createdCmHandles = createdCmHandles
- dmiPluginRegistration.updatedCmHandles = updatedCmHandles
- and: 'an JSON processing exception occurs'
- spyObjectMapper.writeValueAsString(_) >> { throw (new JsonProcessingException('')) }
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'a data validation exception is thrown'
- thrown(DataValidationException)
- where:
- scenario | createdCmHandles | updatedCmHandles
- 'create' | [persistenceCmHandle] | []
- 'update' | [] | [persistenceCmHandle]
- }
-
- def 'Register a DMI Plugin with no data found during delete.'() {
- given: 'a registration without cmHandle properties '
- NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.removedCmHandles = ['some cm handle']
- and: 'an JSON processing exception occurs'
- mockCpsDataService.deleteListOrListElement(*_) >> { throw (new DataNodeNotFoundException('','')) }
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'no exception is thrown'
- noExceptionThrown()
- }
-
- def 'Get resource data for pass-through operational from dmi.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'data node is got from data service'
+ def 'Write resource data for passthrough running from dmi using POST #scenario cm handle properties.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(includeCmHandleProperties)
+ and: 'cpsDataService returns valid datanode'
mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'resource data is got from DMI'
- mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('result-json', HttpStatus.OK)
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'dmi returns ok response'
- response == 'result-json'
- }
-
- def 'Get resource data for pass-through operational from dmi threw parsing exception.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cps data service returns valid cmHandle data node'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'objectMapper not able to parse object'
- def mockObjectMapper = Mock(ObjectMapper)
- objectUnderTest.objectMapper = mockObjectMapper
- mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown with the expected details'
- def exceptionThrown = thrown(NcmpException.class)
- exceptionThrown.details == 'testException'
- }
-
- def 'Get resource data for pass-through operational from dmi return NOK response.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cps data service returns valid cmHandle data node'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi returns NOK response'
- mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
- >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown'
- def exceptionThrown = thrown(NcmpException.class)
- and: 'details contains the original response'
- exceptionThrown.details.contains('NOK-json')
- }
-
- def 'Get resource data for pass-through running from dmi.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cpsDataService returns valid dataNode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi returns valid response and data'
- mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'get resource data returns expected response'
- response == '{result-json}'
- }
-
- def 'Get resource data for pass-through running from dmi threw parsing exception.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cpsDataService returns valid dataNode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'objectMapper not able to parse object'
- def mockObjectMapper = Mock(ObjectMapper)
- objectUnderTest.objectMapper = mockObjectMapper
- mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown with the expected details'
- def exceptionThrown = thrown(NcmpException.class)
- exceptionThrown.details == 'testException'
- }
-
- def 'Get resource data for pass-through running from dmi return NOK response.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cpsDataService returns valid dataNode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi returns NOK response'
- mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
- >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown'
- def exceptionThrown = thrown(NcmpException.class)
- and: 'details contains the original response'
- exceptionThrown.details.contains('NOK-json')
- }
-
- def 'Write resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
- given: 'data node representing cmHandle #scenario cm handle properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(includeCmHandleProperties)
- and: 'cpsDataService returns valid cm-handle datanode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- when: 'get resource data is called'
- objectUnderTest.createResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- '{some-json}', 'application/json')
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', CREATE,
+ '{some-json}', 'application/json')
then: 'dmi called with correct data'
- 1 * mockDmiOperations.createResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '{"operation":"create","dataType":"application/json","data":"{some-json}","cmHandleProperties":'
- + expectedJsonForCmhandleProperties+ '}')
+ 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
+ CREATE, '{some-json}', 'application/json')
>> { new ResponseEntity<>(HttpStatus.CREATED) }
where:
scenario | includeCmHandleProperties || expectedJsonForCmhandleProperties
@@ -378,57 +117,148 @@
'without' | false || '{}'
}
- def 'Write resource data for pass-through running from dmi using POST "not found" response (from DMI).'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
+ def 'Write resource data for passthrough running from dmi using POST "not found" response (from DMI).'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
and: 'cpsDataService returns valid dataNode'
mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi throws exception'
- mockDmiOperations.createResourceDataPassThroughRunningFromDmi(_ as String, _ as String, _ as String, _ as String)
- >> { new ResponseEntity<>(HttpStatus.NOT_FOUND) }
- when: 'get resource data is called'
- objectUnderTest.createResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- '{some-json}', 'application/json')
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns a response with 404 status code'
+ mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle',
+ 'testResourceId', CREATE,
+ '{some-json}', 'application/json')
+ >> { new ResponseEntity<>(HttpStatus.NOT_FOUND) }
+ when: 'write resource data is called'
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', CREATE,
+ '{some-json}', 'application/json')
then: 'exception is thrown'
def exceptionThrown = thrown(NcmpException.class)
and: 'details contains (not found) error code: 404'
exceptionThrown.details.contains('404')
}
- def 'Sync model for a (new) cm handle with #scenario'() {
- given: 'persistence cm handle is given'
- def cmHandleForModelSync = new PersistenceCmHandle(id:'some cm handle', dmiServiceName: 'some service name')
- and: 'additional properties are set as required'
- if (additionalProperties!=null) {
- cmHandleForModelSync.setAdditionalProperties(additionalProperties)
- }
- and: 'dmi operations returns some module references'
- def jsonData = TestUtils.getResourceFileContent('cmHandleModules.json')
- def expectedJsonBody = '{"cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
- mockDmiProperties.getAuthUsername() >> 'someUser'
- mockDmiProperties.getAuthPassword() >> 'somePassword'
- def moduleReferencesFromCmHandleAsJson = new ResponseEntity<String>(jsonData, HttpStatus.OK)
- mockDmiOperations.getResourceFromDmiWithJsonData('some service name', expectedJsonBody, 'some cm handle', 'modules') >> moduleReferencesFromCmHandleAsJson
- and: 'CPS-Core returns list of known modules'
- mockCpsModuleService.getYangResourceModuleReferences(_) >> existingModuleResourcesInCps
- and: 'DMI-Plugin returns resource(s) for "new" module(s)'
- def moduleResources = new ResponseEntity<String>(sdncReponseBody, HttpStatus.OK)
- def jsonDataToFetchYangResource = '{"data":{"modules":[{"name":"module1","revision":"1"}]},"cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
- mockDmiOperations.getResourceFromDmiWithJsonData('some service name', jsonDataToFetchYangResource, 'some cm handle', 'moduleResources') >> moduleResources
- when: 'module Sync is triggered'
- objectUnderTest.syncModulesAndCreateAnchor(cmHandleForModelSync)
- then: 'the CPS module service is called once with the correct parameters'
- 1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), expectedYangResourceToContentMap, expectedKnownModules)
- and: 'admin service create anchor method has been called with correct parameters'
- 1 * mockCpsAdminService.createAnchor(expectedDataspaceName, cmHandleForModelSync.getId(), cmHandleForModelSync.getId())
- where: 'the following responses are received from SDNC'
- scenario | additionalProperties | existingModuleResourcesInCps | sdncReponseBody || expectedYangResourceToContentMap | expectedKnownModules | expectedJsonForAdditionalProperties
- 'one unknown module' | ['name1':'value1'] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{"name1":"value1"}'
- 'no add. properties' | [:] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{}'
- 'additional properties is null' | null | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{}'
- 'no unknown module' | [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '[]' || [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] |'{}'
+ def 'Get data node.'() {
+ when: 'get data node is invoked'
+ objectUnderTest.getDataNode(cmHandle, 'some xpath', fetchDescendantsOption)
+ then: 'the persistence data service is called once with the correct parameters'
+ 1 * mockCpsDataService.getDataNode(expectedDataspaceName, cmHandle, 'some xpath', fetchDescendantsOption)
+ where: 'all fetch descendants options are supported'
+ fetchDescendantsOption << FetchDescendantsOption.values()
+ }
+
+ def 'Get resource data for passthrough operational from dmi.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'get data node is called'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'get resource data from dmi is called'
+ mockDmiDataOperations.getResourceDataFromDmi(
+ 'testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam' ,
+ PASSTHROUGH_OPERATIONAL) >> new ResponseEntity<>('result-json', HttpStatus.OK)
+ when: 'get resource data operational for cm-handle is called'
+ def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'dmi returns a json response'
+ response == 'result-json'
+ }
+
+ def 'Get resource data for passthrough operational from dmi with Json Processing Exception.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cps data service returns valid data node'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'objectMapper not able to parse object'
+ def mockObjectMapper = Mock(ObjectMapper)
+ objectUnderTest.objectMapper = mockObjectMapper
+ mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
+ and: 'dmi returns NOK response'
+ mockDmiDataOperations.getResourceDataFromDmi(*_)
+ >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'exception is thrown with the expected details'
+ def exceptionThrown = thrown(NcmpException.class)
+ exceptionThrown.details == 'DMI status code: 404, DMI response body: NOK-json'
+ }
+
+ def 'Get resource data for passthrough operational from dmi return NOK response.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cps data service returns valid data node'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns NOK response'
+ mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam',
+ PASSTHROUGH_OPERATIONAL)
+ >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'exception is thrown'
+ def exceptionThrown = thrown(NcmpException.class)
+ and: 'details contains the original response'
+ exceptionThrown.details.contains('NOK-json')
+ }
+
+ def 'Get resource data for passthrough running from dmi.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cpsDataService returns valid data node'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns valid response and data'
+ mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam',
+ PASSTHROUGH_RUNNING) >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
+ when: 'get resource data is called'
+ def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'get resource data returns expected response'
+ response == '{result-json}'
+ }
+
+ def 'Get resource data for passthrough running from dmi return NOK response.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cpsDataService returns valid dataNode'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns NOK response'
+ mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam',
+ PASSTHROUGH_RUNNING)
+ >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'exception is thrown'
+ def exceptionThrown = thrown(NcmpException.class)
+ and: 'details contains the original response'
+ exceptionThrown.details.contains('NOK-json')
}
def 'Getting Yang Resources.'() {
@@ -438,18 +268,6 @@
1 * mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some cm handle')
}
- def 'Create the request body to get yang resources from DMI.'() {
- given: 'the expected json request'
- def expectedRequestBody = '{"data":{"modules":[{"name":"module1","revision":"1"},{"name":"module2","revision":"2"}]},"cmHandleProperties":{"name1":"value1"}}'
- and: 'module references and cm handle properties'
- def moduleReferences = [new ModuleReference('module1', '1'),new ModuleReference('module2', '2')]
- def cmHandleProperties = ['name1':'value1']
- when: 'get request body to fetch yang resources from DMI is called'
- def result = objectUnderTest.getRequestBodyToFetchYangResourceFromDmi(moduleReferences, cmHandleProperties)
- then: 'the result is the same as the expected request body'
- result == expectedRequestBody
- }
-
def 'Get cm handle identifiers for the given module names.'() {
when: 'execute a cm handle search for the given module names'
objectUnderTest.executeCmHandleHasAllModulesSearch(['some-module-name'])
@@ -457,45 +275,86 @@
1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name'])
}
- def 'Update resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
- given: 'data node representing cmHandle #scenario cm handle properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(includeCmHandleProperties)
- and: 'cpsDataService returns valid cm-handle datanode'
+ def 'Update data node leaves.'() {
+ given: 'json data and xpath'
+ def jsonData = 'some json'
+ def xpath = '/xpath'
+ when: 'update node leaves is invoked'
+ objectUnderTest.updateNodeLeaves(cmHandle, xpath, jsonData)
+ then: 'the persistence service is called once with the correct parameters'
+ 1 * mockCpsDataService.updateNodeLeaves(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
+ }
+
+ def 'Replace data node tree.'() {
+ given: 'json data and xpath'
+ def jsonData = 'some json'
+ def xpath = '/xpath'
+ when: 'replace node tree is invoked'
+ objectUnderTest.replaceNodeTree(cmHandle, xpath, jsonData)
+ then: 'the persistence service is called once with the correct parameters'
+ 1 * mockCpsDataService.replaceNodeTree(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
+ }
+
+ def 'Update resource data for passthrough running from dmi using POST #scenario cm handle properties.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(includeCmHandleProperties)
+ and: 'cpsDataService returns valid datanode'
mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- when: 'update resource data is called'
- objectUnderTest.updateResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- '{some-json}', 'application/json')
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ when: 'get resource data is called'
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', UPDATE,
+ '{some-json}', 'application/json')
then: 'dmi called with correct data'
- 1 * mockDmiOperations.updateResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '{"operation":"update","dataType":"application/json","data":"{some-json}","cmHandleProperties":'
- + expectedJsonForCmhandleProperties + '}')
- >> new ResponseEntity<>(HttpStatus.OK)
+ 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
+ UPDATE, '{some-json}', 'application/json')
+ >> { new ResponseEntity<>(HttpStatus.OK) }
where:
scenario | includeCmHandleProperties || expectedJsonForCmhandleProperties
'with' | true || '{"testName":"testValue"}'
'without' | false || '{}'
}
- def getObjectUnderTestWithModelSyncDisabled() {
- def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
- mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper))
- objectUnderTest.syncModulesAndCreateAnchor(_) >> null
- return objectUnderTest
+ def 'Verify error message from handleResponse is correct for #scenario operation.'() {
+ given: 'writeResourceDataPassThroughRunningFromDmi fails to return OK HttpStatus'
+ mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi(*_)
+ >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ def response = objectUnderTest.writeResourceDataPassThroughRunningForCmHandle(
+ 'testCmHandle',
+ 'testResourceId',
+ givenOperation,
+ '{some-json}',
+ 'application/json')
+ then: 'an exception is thrown with the expected error message detailsd with correct operation'
+ def exceptionThrown = thrown(NcmpException.class)
+ exceptionThrown.getMessage().contains(expectedResponseMessage)
+ where:
+ scenario | givenOperation || expectedResponseMessage
+ 'CREATE' | CREATE || 'Not able to create resource data.'
+ 'READ' | READ || 'Not able to read resource data.'
+ 'UPDATE' | UPDATE || 'Not able to update resource data.'
}
- def getCmHandleDataNodeForTest(boolean includeCmHandleProperties) {
- def cmHandleDataNode = new DataNode()
- cmHandleDataNode.leaves = ['dmi-service-name': 'testDmiService']
+ def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
+ given: 'a cps path'
+ def cpsPath = '/cps-path'
+ when: 'query data nodes is invoked'
+ objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
+ then: 'the persistence query service is called once with the correct parameters'
+ 1 * mockCpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
+ where: 'all fetch descendants options are supported'
+ fetchDescendantsOption << FetchDescendantsOption.values()
+ }
+
+ def getDataNode(boolean includeCmHandleProperties) {
+ def dataNode = new DataNode()
+ dataNode.leaves = ['dmi-service-name': 'testDmiService']
if (includeCmHandleProperties) {
def cmHandlePropertyDataNode = new DataNode()
cmHandlePropertyDataNode.leaves = ['name': 'testName', 'value': 'testValue']
- cmHandleDataNode.childDataNodes = [cmHandlePropertyDataNode]
+ dataNode.childDataNodes = [cmHandlePropertyDataNode]
}
- return cmHandleDataNode
+ return dataNode
}
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operation/DmiOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operation/DmiOperationsSpec.groovy
deleted file mode 100644
index 44d4f0c..0000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operation/DmiOperationsSpec.groovy
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021 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.operation
-
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
-import org.spockframework.spring.SpringBean
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.http.HttpHeaders
-import org.springframework.test.context.ContextConfiguration
-import spock.lang.Specification
-
-@SpringBootTest
-@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiOperations])
-class DmiOperationsSpec extends Specification {
-
- @SpringBean
- DmiRestClient mockDmiRestClient = Mock()
-
- @Autowired
- DmiOperations objectUnderTest = new DmiOperations(mockDmiRestClient)
-
- def 'call get resource data for pass-through:operational datastore from DMI.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child&options=(a=1,b=2)'
- when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataOperationalFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- '(a=1,b=2)',
- 'testAcceptJson',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
- def 'call get resource data for pass-through:running datastore from DMI.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-running?resourceIdentifier=parent/child&options=(a=1,b=2)'
- when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataPassThroughRunningFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- '(a=1,b=2)',
- 'testAcceptJson',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
- def 'call get resource data for pass-through:operational datastore from DMI when options is null.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child'
- when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataOperationalFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- null,
- 'testAcceptJson',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
- def 'call create resource data for pass-through:running datastore from DMI.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-running?resourceIdentifier=parent/child'
- when: 'get resource data is called to DMI'
- objectUnderTest.createResourceDataPassThroughRunningFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
-
- def 'Call get resource from dmi.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/modules'
- when: 'get resource data is called to dmi'
- objectUnderTest.getResourceFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'modules')
- then: 'the post operation is executed with the correct URL'
- 1 * mockDmiRestClient.postOperation(expectedUrl, _ as HttpHeaders)
- }
-
- def 'Call get resource from dmi with json data.'() {
- given: 'expected url & json data'
- def requestBody = 'some json'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmHandle/modules'
- def expectedHttpHeaders = new HttpHeaders()
- when: 'get resource data is called to dmi'
- objectUnderTest.getResourceFromDmiWithJsonData('testDmiBasePath',
- requestBody,
- 'testCmHandle',
- 'modules')
- then: 'the post operation is executed with the correct URL and json data'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, requestBody, expectedHttpHeaders)
- }
-
- def 'Update resource data for pass-through:running datastore from DMI.'() {
- given: 'the expected url'
- def cmHandle = 'some-cmhandle'
- def resourceIdentifier = 'parent/child'
- def expectedUrl = 'some-dmi-service-name/dmi/v1/ch/' + cmHandle + '/data/ds' +
- '/ncmp-datastore:passthrough-running?resourceIdentifier=' + resourceIdentifier
- when: 'replace resource data is called for DMI'
- objectUnderTest.updateResourceDataPassThroughRunningFromDmi('some-dmi-service-name',
- cmHandle,
- resourceIdentifier,
- 'some-json-body')
- then: 'the post operation is executed with the correct URL'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, 'some-json-body', _ as HttpHeaders)
- }
-}
\ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
new file mode 100644
index 0000000..674a442
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
@@ -0,0 +1,84 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations
+
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.ResponseEntity
+import org.springframework.test.context.ContextConfiguration
+
+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
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE
+import org.springframework.http.HttpStatus
+
+@SpringBootTest
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiDataOperations])
+class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
+
+ @Autowired
+ DmiDataOperations objectUnderTest
+
+ def 'call get resource data for #expectedDatastoreInUrl from DMI #scenario.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(additionalProperties)
+ and: 'a positive response from dmi service when it is called with the expected parameters'
+ def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
+ mockDmiRestClient.putOperationWithJsonData(
+ "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds/ncmp-datastore:${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}",
+ expectedJson, [Accept:['sample accept header']]) >> responseFromDmi
+ when: 'get resource data is invoked'
+ def result = objectUnderTest.getResourceDataFromDmi(cmHandleId,resourceIdentifier, options,'sample accept header', dataStore)
+ then: 'the result is the response from the dmi service'
+ assert result == responseFromDmi
+ where: 'the following parameters are used'
+ scenario | additionalProperties | dataStore | options || expectedJson | expectedDatastoreInUrl | expectedOptionsInUrl
+ 'without properties' | [] | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
+ 'null properties' | null | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
+ 'with properties' | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
+ 'null options' | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | null || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
+ 'empty options' | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | '' || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
+ 'datastore running' | [] | PASSTHROUGH_RUNNING | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-running' | '&options=(a=1,b=2)'
+ }
+
+ def 'Write data for pass-through:running datastore in DMI.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval([sampleAdditionalProperty])
+ and: 'a positive response from dmi service when it is called with the expected parameters'
+ def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds" +
+ "/ncmp-datastore:passthrough-running?resourceIdentifier=${resourceIdentifier}"
+ def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"}}'
+ def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
+ mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, [:]) >> responseFromDmi
+ when: 'write resource method is invoked'
+ def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId,'parent/child', operation, 'requestData', 'some data type')
+ then: 'the result is the response from the dmi service'
+ assert result == responseFromDmi
+ where: 'the following operation is performed'
+ operation || expectedOperationInUrl
+ CREATE || 'create'
+ UPDATE || 'update'
+ }
+
+}
\ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
new file mode 100644
index 0000000..d9d1271
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
@@ -0,0 +1,103 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations
+
+import com.fasterxml.jackson.core.JsonProcessingException
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.onap.cps.ncmp.api.impl.exception.NcmpException
+import org.onap.cps.spi.model.ModuleReference
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.test.context.ContextConfiguration
+import spock.lang.Shared
+
+@SpringBootTest
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiModelOperations])
+class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
+
+ @Shared
+ def newModuleReferences = [new ModuleReference('mod1','A'), new ModuleReference('mod2','X')]
+
+ @Autowired
+ DmiModelOperations objectUnderTest
+
+ def 'Module references for a persistence cm handle #scenario.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(additionalPropertiesObject)
+ and: 'a positive response from dmi service when it is called with tha expected parameters'
+ def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
+ mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
+ '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', [:]) >> responseFromDmi
+ when: 'a get module references is called'
+ def result = objectUnderTest.getModuleReferences(persistenceCmHandle)
+ then: 'the result is the response from dmi service'
+ assert result == responseFromDmi
+ where:
+ scenario | additionalPropertiesObject || expectedAdditionalPropertiesInRequest
+ 'with properties' | [sampleAdditionalProperty] || '{"prop1":"val1"}'
+ 'with null properties' | null || "{}"
+ 'without properties' | [] || "{}"
+ }
+
+ def 'New yang resources from dmi using persistence cm handle #scenario.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(additionalPropertiesObject)
+ and: 'a positive response from dmi service when it is called with tha expected parameters'
+ def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
+ mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+ '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":'+expectedAdditionalPropertiesInRequest+'}',
+ [:]) >> responseFromDmi
+ when: 'get new yang resources from dmi service'
+ def result = objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, unknownModuleReferences)
+ then: 'the result is the response from dmi service'
+ assert result == responseFromDmi
+ where:
+ scenario | additionalPropertiesObject | unknownModuleReferences || expectedAdditionalPropertiesInRequest | expectedModuleReferencesInRequest
+ 'with module references and properties' | [sampleAdditionalProperty] | newModuleReferences || '{"prop1":"val1"}' | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
+ 'without module references' | [sampleAdditionalProperty] | [] || '{"prop1":"val1"}' | ''
+ 'without properties' | [] | newModuleReferences || '{}' | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
+ }
+
+ def 'New yang resources from dmi with additional properties null'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(null)
+ when: 'a get new yang resources from dmi is called'
+ objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, [])
+ then: 'a null pointer is thrown (we might need to address this later)'
+ thrown(NullPointerException)
+ }
+
+ def 'Json Processing Exception'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval([])
+ and: 'a Json processing exception occurs'
+ spyObjectMapper.writeValueAsString(_) >> {throw (new JsonProcessingException(''))}
+ when: 'a dmi operation is executed'
+ objectUnderTest.getModuleReferences(persistenceCmHandle)
+ then: 'an ncmp exception is thrown'
+ def exceptionThrown = thrown(NcmpException)
+ and: 'the message indicates a parsing error'
+ exceptionThrown.message.toLowerCase().contains("parsing error")
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
new file mode 100644
index 0000000..4bf7dad
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
@@ -0,0 +1,36 @@
+package org.onap.cps.ncmp.api.impl.operations
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle
+import org.spockframework.spring.SpringBean
+import spock.lang.Shared
+import spock.lang.Specification
+
+abstract class DmiOperationsBaseSpec extends Specification {
+
+ @Shared
+ def sampleAdditionalProperty = new PersistenceCmHandle.AdditionalProperty('prop1', 'val1')
+
+ @SpringBean
+ DmiRestClient mockDmiRestClient = Mock()
+
+ @SpringBean
+ PersistenceCmHandleRetriever mockCmHandlePropertiesRetriever = Mock()
+
+ @SpringBean
+ ObjectMapper spyObjectMapper = Spy()
+
+ def persistenceCmHandle = new PersistenceCmHandle()
+ def static dmiServiceName = 'some service name'
+ def static cmHandleId = 'some cm handle'
+ def static resourceIdentifier = 'parent/child'
+
+ def mockPersistenceCmHandleRetrieval(additionalProperties) {
+ persistenceCmHandle.dmiDataServiceName = dmiServiceName
+ persistenceCmHandle.dmiServiceName = dmiServiceName
+ persistenceCmHandle.additionalProperties = additionalProperties
+ persistenceCmHandle.id = cmHandleId
+ mockCmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndProperties(cmHandleId) >> persistenceCmHandle
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy
new file mode 100644
index 0000000..3ab9266
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy
@@ -0,0 +1,44 @@
+package org.onap.cps.ncmp.api.impl.operations
+
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle
+import spock.lang.Shared
+
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import org.onap.cps.spi.model.DataNode
+import spock.lang.Specification
+
+class PersistenceCmHandleRetrieverSpec extends Specification {
+
+ def mockCpsDataService = Mock(CpsDataService)
+
+ def objectUnderTest = new PersistenceCmHandleRetriever(mockCpsDataService)
+
+ def cmHandleId = 'some cm handle'
+ def leaves = ["dmi-service-name":"common service name","dmi-data-service-name":"data service name","dmi-model-service-name":"model service name"]
+ def xpath = "/dmi-registry/cm-handles[@id='some cm handle']"
+
+ @Shared
+ def childDataNodesForCmHandleProperties = [new DataNode(leaves: ["name":"name1","value":"value1"]),
+ new DataNode(leaves: ["name":"name2","value":"value2"])]
+
+ def "Retrieve CmHandle using datanode #scenario."() {
+ given: 'the cps data service returns a data node from the dmi registry'
+ def dataNode = new DataNode(childDataNodes:childDataNodes, leaves: leaves)
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode
+ when: 'retrieving the persisted cm handle'
+ def result = objectUnderTest.retrieveCmHandleDmiServiceNameAndProperties(cmHandleId)
+ then: 'the result has the correct id and service names'
+ result.id == cmHandleId
+ result.dmiServiceName == 'common service name'
+ result.dmiDataServiceName == 'data service name'
+ result.dmiModelServiceName == 'model service name'
+ and: 'the expected additional properties'
+ result.additionalProperties == expectedCmHandleProperties
+ where: 'the following parameters are used'
+ scenario | childDataNodes || expectedCmHandleProperties
+ 'without additional properties' | [] || []
+ 'with additional properties' | childDataNodesForCmHandleProperties || [new PersistenceCmHandle.AdditionalProperty("name1", "value1"),
+ new PersistenceCmHandle.AdditionalProperty("name2", "value2")]
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
index bfed795..c66eaa9 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
@@ -21,13 +21,15 @@
import spock.lang.Specification
-class PersistenceCmHandleSpec extends Specification {
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL
- def objectUnderTest = new PersistenceCmHandle()
+class PersistenceCmHandleSpec extends Specification {
def 'Setting and getting additional properties.'() {
given: 'a map of one property is added'
- objectUnderTest.setAdditionalProperties([myProperty: 'some value'])
+ def objectUnderTest = new PersistenceCmHandle()
+ objectUnderTest.asAdditionalProperties([myProperty: 'some value'])
when: 'the additional properties are retrieved'
def result = objectUnderTest.getAdditionalProperties()
then: 'the result has the right size'
@@ -39,4 +41,23 @@
assert actualAdditionalProperty.value == expectedAdditionalProperty.value
}
+ def 'Resolve dmi service name: #scenario and #requiredService service require.'() {
+ given: 'a Persistence CM Handle'
+ def objectUnderTest = PersistenceCmHandle.toPersistenceCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new CmHandle('some id', null))
+ expect:
+ assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService
+ where:
+ scenario | dmiServiceName | dmiDataServiceName | dmiModelServiceName | requiredService || expectedService
+ 'common service registered' | 'common service' | 'does not matter' | 'does not matter' | DATA || 'common service'
+ 'common service registered' | 'common service' | 'does not matter' | 'does not matter' | MODEL || 'common service'
+ 'common service empty' | '' | 'data service' | 'does not matter' | DATA || 'data service'
+ 'common service empty' | '' | 'does not matter' | 'model service' | MODEL || 'model service'
+ 'common service blank' | ' ' | 'data service' | 'does not matter' | DATA || 'data service'
+ 'common service blank' | ' ' | 'does not matter' | 'model service' | MODEL || 'model service'
+ 'common service null ' | null | 'data service' | 'does not matter' | DATA || 'data service'
+ 'common service null' | null | 'does not matter' | 'model service' | MODEL || 'model service'
+ 'only model service registered' | null | null | 'does not matter' | DATA || null
+ 'only data service registered' | null | 'does not matter' | null | MODEL || null
+ }
+
}
diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml
index 71ac2c9..d8fbb64 100644
--- a/cps-ncmp-service/src/test/resources/application.yml
+++ b/cps-ncmp-service/src/test/resources/application.yml
@@ -20,4 +20,6 @@
auth:
username: some-user
password: some-password
+ api:
+ base-path: /dmi