summaryrefslogtreecommitdiffstats
path: root/dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy
diff options
context:
space:
mode:
Diffstat (limited to 'dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy')
-rw-r--r--dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy273
1 files changed, 273 insertions, 0 deletions
diff --git a/dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy b/dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy
new file mode 100644
index 00000000..8531d35f
--- /dev/null
+++ b/dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy
@@ -0,0 +1,273 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2022 Nordix Foundation
+ * Modifications Copyright (C) 2021-2022 Bell Canada
+ * ================================================================================
+ * 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.dmi.service
+
+import com.fasterxml.jackson.core.JsonProcessingException
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.databind.ObjectWriter
+import org.onap.cps.ncmp.dmi.config.DmiPluginConfig
+import org.onap.cps.ncmp.dmi.exception.CmHandleRegistrationException
+import org.onap.cps.ncmp.dmi.exception.DmiException
+import org.onap.cps.ncmp.dmi.exception.ModuleResourceNotFoundException
+import org.onap.cps.ncmp.dmi.exception.ModulesNotFoundException
+import org.onap.cps.ncmp.dmi.exception.HttpClientRequestException
+import org.onap.cps.ncmp.dmi.service.model.ModuleReference
+import org.onap.cps.ncmp.dmi.model.YangResource
+import org.onap.cps.ncmp.dmi.model.YangResources
+import org.onap.cps.ncmp.dmi.service.client.NcmpRestClient
+import org.onap.cps.ncmp.dmi.service.model.ModuleSchema
+import org.onap.cps.ncmp.dmi.service.operation.SdncOperations
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import spock.lang.Specification
+
+import static org.onap.cps.ncmp.dmi.model.DataAccessRequest.OperationEnum.CREATE
+import static org.onap.cps.ncmp.dmi.model.DataAccessRequest.OperationEnum.UPDATE
+
+class DmiServiceImplSpec extends Specification {
+
+
+ def mockNcmpRestClient = Mock(NcmpRestClient)
+ def mockDmiPluginProperties = Mock(DmiPluginConfig.DmiPluginProperties)
+ def spyObjectMapper = Spy(ObjectMapper)
+ def mockObjectMapper = Mock(ObjectMapper)
+ def mockSdncOperations = Mock(SdncOperations)
+ def objectUnderTest = new DmiServiceImpl(mockDmiPluginProperties, mockNcmpRestClient, mockSdncOperations, spyObjectMapper)
+
+ def 'Register cm handles with ncmp.'() {
+ given: 'some cm-handle ids'
+ def givenCmHandlesList = ['node1', 'node2']
+ and: 'json payload'
+ def expectedJson = '{"dmiPlugin":"test-dmi-service","createdCmHandles":[{"cmHandle":"node1"},{"cmHandle":"node2"}]}'
+ and: 'process returns "test-dmi-service" for service name'
+ mockDmiPluginProperties.getDmiServiceUrl() >> 'test-dmi-service'
+ when: 'the cm handles are registered'
+ objectUnderTest.registerCmHandles(givenCmHandlesList)
+ then: 'register cm handle with ncmp is called with the expected json and return "created" status'
+ 1 * mockNcmpRestClient.registerCmHandlesWithNcmp(expectedJson) >> new ResponseEntity<>(HttpStatus.CREATED)
+ }
+
+ def 'Register cm handles with ncmp called with exception #scenario.'() {
+ given: 'some cm-handle ids'
+ def cmHandlesList = ['node1', 'node2']
+ and: 'process returns "test-dmi-service" for service name'
+ mockDmiPluginProperties.getDmiServiceUrl() >> 'test-dmi-service'
+ and: 'returns #responseEntity'
+ mockNcmpRestClient.registerCmHandlesWithNcmp(_ as String) >> responseEntity
+ when: 'the cm handles are registered'
+ objectUnderTest.registerCmHandles(cmHandlesList)
+ then: 'a registration exception is thrown'
+ thrown(CmHandleRegistrationException.class)
+ where: 'given #scenario'
+ scenario | responseEntity
+ 'ncmp rest client returns bad request' | new ResponseEntity<>(HttpStatus.BAD_REQUEST)
+ 'ncmp rest client returns internal server error' | new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)
+ }
+
+ def 'Register cm handles with ncmp with wrong data.'() {
+ given: 'some cm-handle ids'
+ def cmHandlesList = ['node1', 'node2']
+ and: ' "JsonProcessingException" occurs during parsing'
+ objectUnderTest.objectMapper = mockObjectMapper
+ mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('some error.') }
+ when: 'the cmHandles are registered'
+ objectUnderTest.registerCmHandles(cmHandlesList)
+ then: 'a dmi exception is thrown'
+ thrown(DmiException.class)
+ }
+
+ def ' Get modules for a cm-handle.'() {
+ given: 'a cm handle'
+ def cmHandle = 'node1'
+ and: 'process returns one module schema for the cmhandle'
+ def moduleSchema = new ModuleSchema(
+ identifier: "example-identifier",
+ namespace: "example:namespace",
+ version: "example-version")
+ mockSdncOperations.getModuleSchemasFromNode(cmHandle) >> List.of(moduleSchema)
+ when: 'modules for cmHandle is requested'
+ def result = objectUnderTest.getModulesForCmHandle(cmHandle)
+ then: 'one module is returned'
+ result.schemas.size() == 1
+ and: 'module has expected values'
+ with(result.schemas[0]) {
+ it.getRevision() == moduleSchema.getVersion()
+ it.getModuleName() == moduleSchema.getIdentifier()
+ it.getNamespace() == moduleSchema.getNamespace();
+ }
+ }
+
+ def 'no modules found for the cmhandle.'() {
+ given: 'cm handle id'
+ def cmHandle = 'node1'
+ and: 'process returns no modules'
+ mockSdncOperations.getModuleSchemasFromNode(cmHandle) >> Collections.emptyList();
+ when: 'modules for cm-handle is requested'
+ objectUnderTest.getModulesForCmHandle(cmHandle)
+ then: 'module not found exception is thrown'
+ thrown(ModulesNotFoundException)
+ }
+
+ def 'Get multiple module resources.'() {
+ given: 'a cmHandle'
+ def cmHandle = 'some-cmHandle'
+ and: 'multiple module references'
+ def moduleReference1 = new ModuleReference(name: 'name-1', revision: 'revision-1')
+ def moduleReference2 = new ModuleReference(name: 'name-2', revision: 'revision-2')
+ def moduleList = [moduleReference1, moduleReference2]
+ when: 'module resources is requested'
+ def result = objectUnderTest.getModuleResources(cmHandle, moduleList)
+ then: 'SDNC operation service is called same number of module references given'
+ 2 * mockSdncOperations.getModuleResource(cmHandle, _) >>> [new ResponseEntity<String>('{"ietf-netconf-monitoring:output": {"data": "some-data1"}}', HttpStatus.OK),
+ new ResponseEntity<String>('{"ietf-netconf-monitoring:output": {"data": "some-data2"}}', HttpStatus.OK)]
+ and: 'the result contains the expected properties'
+ def yangResources = new YangResources()
+ def yangResource1 = new YangResource(yangSource: 'some-data1', moduleName: 'name-1', revision: 'revision-1')
+ def yangResource2 = new YangResource(yangSource: 'some-data2', moduleName: 'name-2', revision: 'revision-2')
+ yangResources.add(yangResource1)
+ yangResources.add(yangResource2)
+ assert result == yangResources
+ }
+
+ def 'Get a module resource with module resource not found exception for #scenario.'() {
+ given: 'a cmHandle and module reference list'
+ def cmHandle = 'some-cmHandle'
+ def moduleReference = new ModuleReference(name: 'NAME', revision: 'REVISION')
+ def moduleList = [moduleReference]
+ when: 'module resources is requested'
+ objectUnderTest.getModuleResources(cmHandle, moduleList)
+ then: 'SDNC operation service is called once with a response body that contains no data'
+ 1 * mockSdncOperations.getModuleResource(cmHandle, _) >> new ResponseEntity<String>(responseBody, HttpStatus.OK)
+ and: 'an exception is thrown'
+ thrown(ModuleResourceNotFoundException)
+ where: 'the following values are returned'
+ scenario | responseBody
+ 'a response body containing no data object' | '{"ietf-netconf-monitoring:output": {"null": "some-data"}}'
+ 'a response body containing no ietf-netconf-monitoring:output object' | '{"null": {"data": "some-data"}}'
+ }
+
+ def 'Get module resources when sdnc returns #scenario response.'() {
+ given: 'sdnc returns a #scenario response'
+ mockSdncOperations.getModuleResource(_ as String, _ as String) >> new ResponseEntity<String>('some-response-body', httpStatus)
+ when: 'module resources is requested'
+ objectUnderTest.getModuleResources('some-cmHandle', [new ModuleReference()] as LinkedList<ModuleReference>)
+ then: '#expectedException is thrown'
+ thrown(expectedException)
+ where: 'the following values are returned'
+ scenario | httpStatus || expectedException
+ 'not found' | HttpStatus.NOT_FOUND || ModuleResourceNotFoundException
+ 'internal server error' | HttpStatus.INTERNAL_SERVER_ERROR || DmiException
+ }
+
+ def 'Get module resources with JSON processing exception.'() {
+ given: 'a json processing exception during process'
+ def mockObjectWriter = Mock(ObjectWriter)
+ spyObjectMapper.writer() >> mockObjectWriter
+ mockObjectWriter.withRootName(_) >> mockObjectWriter
+ def jsonProcessingException = new JsonProcessingException('')
+ mockObjectWriter.writeValueAsString(_) >> { throw jsonProcessingException }
+ when: 'module resources is requested'
+ objectUnderTest.getModuleResources('some-cmHandle', [new ModuleReference()] as LinkedList<ModuleReference>)
+ then: 'an exception is thrown'
+ def thrownException = thrown(DmiException.class)
+ and: 'the exception has the expected message and details'
+ thrownException.message == 'Unable to process JSON.'
+ thrownException.details == 'JSON exception occurred when creating the module request.'
+ and: 'the cause is the original json processing exception'
+ thrownException.cause == jsonProcessingException
+ }
+
+ def 'Get resource data for passthrough operational.'() {
+ given: 'sdnc operation returns OK response'
+ mockSdncOperations.getResouceDataForOperationalAndRunning(
+ 'someCmHandle',
+ 'someResourceId',
+ '(fields=x/y/z,depth=10,test=abc)',
+ 'content=all') >> new ResponseEntity<>('response json', HttpStatus.OK)
+ when: 'resource data is requested'
+ def response = objectUnderTest.getResourceData(
+ 'someCmHandle',
+ 'someResourceId',
+ '(fields=x/y/z,depth=10,test=abc)',
+ 'content=all')
+ then: 'response matches the response returned from the SDNC service'
+ response == 'response json'
+ }
+
+ def 'Get resource data with not found exception.'() {
+ given: 'sdnc operation returns "NOT_FOUND" response'
+ mockSdncOperations.getResouceDataForOperationalAndRunning(*_) >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
+ when: 'resource data is requested'
+ objectUnderTest.getResourceData('someCmHandle', 'someResourceId',
+ '(fields=x/y/z,depth=10,test=abc)', 'content=config')
+ then: 'http client request exception'
+ thrown(HttpClientRequestException.class)
+ }
+
+ def 'Get resource data for passthrough running.'() {
+ given: 'sdnc operation returns OK response'
+ mockSdncOperations.getResouceDataForOperationalAndRunning(*_) >> new ResponseEntity<>('response json', HttpStatus.OK)
+ when: 'resource data is requested'
+ def response = objectUnderTest.getResourceData(
+ 'someCmHandle',
+ 'someResourceId',
+ '(fields=x/y/z,depth=10,test=abc)',
+ 'content=config')
+ then: 'response have expected json'
+ response == 'response json'
+ }
+
+ def 'Write resource data for passthrough running with a #scenario from sdnc.'() {
+ given: 'sdnc returns a response with #scenario'
+ mockSdncOperations.writeData(operationEnum, _, _, _, _) >> new ResponseEntity<String>('response json', httpResponse)
+ when: 'resource data is written to sdnc'
+ def response = objectUnderTest.writeData(operationEnum, 'some-cmHandle',
+ 'some-resourceIdentifier', 'some-dataType', '{some-data}')
+ then: 'the response matches the expected data'
+ response == 'response json'
+ where: 'the following values are used'
+ scenario | httpResponse | operationEnum
+ '200 OK with an update operation' | HttpStatus.OK | UPDATE
+ '201 CREATED with a create operation' | HttpStatus.CREATED | CREATE
+ }
+
+ def 'Write resource data with special characters.'() {
+ given: 'sdnc returns a created response'
+ mockSdncOperations.writeData(CREATE, 'some-cmHandle',
+ 'some-resourceIdentifier', 'some-dataType', 'data with quote " and \n new line') >> new ResponseEntity<String>('response json', HttpStatus.CREATED)
+ when: 'resource data is written to sdnc'
+ def response = objectUnderTest.writeData(CREATE, 'some-cmHandle',
+ 'some-resourceIdentifier', 'some-dataType', 'data with quote " and \n new line')
+ then: 'the response matches the expected data'
+ response == 'response json'
+ }
+
+ def 'Write resource data for passthrough running with a 500 response from sdnc.'() {
+ given: 'sdnc returns internal server error response'
+ mockSdncOperations.writeData(CREATE, _, _, _, _) >> new ResponseEntity<String>('response json', HttpStatus.INTERNAL_SERVER_ERROR)
+ when: 'resource data is written to sdnc'
+ objectUnderTest.writeData(CREATE, 'some-cmHandle',
+ 'some-resourceIdentifier', 'some-dataType', _ as String)
+ then: 'a dmi exception is thrown'
+ thrown(DmiException.class)
+ }
+} \ No newline at end of file