From bbaf501627a69707bd797c535750996a9dd205aa Mon Sep 17 00:00:00 2001 From: bmiklos Date: Thu, 25 Aug 2022 18:28:16 +0200 Subject: Implement merging all ncmp datastore endpoints into one - Merging all endpoints under /v1/ch/{cm-handle}/data/ds/ncmp-datastore:* to /v1/ch/{cm-handle}/data/ds/{ncmp-datastore-name} - Implementing missing tests from parent - Introducing abstract class to keep the common code and just pass in the supplier to be executed in sync or async manner - Removed the existing get endpoints for passthrough-running, passthrough-operational and operational and merged them into a common get endpoint Issue-ID: CPS-1178 Issue-ID: CPS-1001 Change-Id: I6956c81d5acfa8fb11217bcc16cb795b62070fa3 Signed-off-by: bmiklos --- .../controller/NetworkCmProxyControllerSpec.groovy | 277 +++++++++++++-------- ...tastoreResourceRequestHandlerFactorySpec.groovy | 20 ++ .../NetworkCmProxyRestExceptionHandlerSpec.groovy | 14 +- .../cps/ncmp/rest/util/TopicValidatorSpec.groovy | 47 ++++ 4 files changed, 250 insertions(+), 108 deletions(-) create mode 100644 cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreResourceRequestHandlerFactorySpec.groovy create mode 100644 cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/TopicValidatorSpec.groovy (limited to 'cps-ncmp-rest/src/test') diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy index d568a5a92..6e461fa59 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy @@ -23,51 +23,59 @@ package org.onap.cps.ncmp.rest.controller +import com.fasterxml.jackson.databind.ObjectMapper import org.mapstruct.factory.Mappers +import org.onap.cps.TestUtils +import org.onap.cps.ncmp.api.NetworkCmProxyDataService import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState -import org.onap.cps.ncmp.api.inventory.LockReasonCategory import org.onap.cps.ncmp.api.inventory.DataStoreSyncState +import org.onap.cps.ncmp.api.inventory.LockReasonCategory import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle -import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper +import org.onap.cps.ncmp.rest.controller.handlers.DatastoreType +import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastoreOperationalResourceRequestHandler +import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastorePassthroughOperationalResourceRequestHandler +import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastorePassthroughRunningResourceRequestHandler +import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastoreResourceRequestHandlerFactory import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor +import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper import org.onap.cps.ncmp.rest.util.DeprecationHelper +import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.ModuleDefinition +import org.onap.cps.spi.model.ModuleReference +import org.onap.cps.utils.JsonObjectMapper +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.test.web.servlet.MockMvc import spock.lang.Shared +import spock.lang.Specification import java.time.OffsetDateTime import java.time.ZoneOffset import java.time.format.DateTimeFormatter -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH import static org.onap.cps.ncmp.api.inventory.CompositeState.DataStores import static org.onap.cps.ncmp.api.inventory.CompositeState.Operational -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put 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 static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.DELETE - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.TestUtils -import org.onap.cps.spi.model.ModuleReference -import org.onap.cps.utils.JsonObjectMapper -import org.onap.cps.ncmp.api.NetworkCmProxyDataService -import org.spockframework.spring.SpringBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.test.web.servlet.MockMvc -import spock.lang.Specification +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete @WebMvcTest(NetworkCmProxyController) class NetworkCmProxyControllerSpec extends Specification { + public static final int TIMEOUT_IN_MS = 2000 + public static final boolean NOTIFICATION_ENABLED = true + @Autowired MockMvc mvc @@ -92,6 +100,9 @@ class NetworkCmProxyControllerSpec extends Specification { @SpringBean DeprecationHelper stubbedDeprecationHelper = Stub() + @SpringBean + NcmpDatastoreResourceRequestHandlerFactory stubbedNcmpDatastoreResourceRequestHandlerFactory = Stub() + @Value('${rest.api.ncmp-base-path}/v1') def ncmpBasePathV1 @@ -104,21 +115,38 @@ class NetworkCmProxyControllerSpec extends Specification { def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) + void setup() { + stubbedNcmpDatastoreResourceRequestHandlerFactory.getNcmpDatastoreResourceRequestHandler( + DatastoreType.OPERATIONAL) >> + new NcmpDatastoreOperationalResourceRequestHandler( + mockNetworkCmProxyDataService, spiedCpsTaskExecutor, TIMEOUT_IN_MS, NOTIFICATION_ENABLED) + + stubbedNcmpDatastoreResourceRequestHandlerFactory.getNcmpDatastoreResourceRequestHandler( + DatastoreType.PASSTHROUGH_OPERATIONAL) >> + new NcmpDatastorePassthroughOperationalResourceRequestHandler( + mockNetworkCmProxyDataService, spiedCpsTaskExecutor, TIMEOUT_IN_MS, NOTIFICATION_ENABLED) + + stubbedNcmpDatastoreResourceRequestHandlerFactory.getNcmpDatastoreResourceRequestHandler( + DatastoreType.PASSTHROUGH_RUNNING) >> + new NcmpDatastorePassthroughRunningResourceRequestHandler( + mockNetworkCmProxyDataService, spiedCpsTaskExecutor, TIMEOUT_IN_MS, NOTIFICATION_ENABLED) + } + def 'Get Resource Data from pass-through operational.'() { given: 'resource data url' def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-operational" + - "?resourceIdentifier=parent/child&options=(a=1,b=2)" + "?resourceIdentifier=parent/child&options=(a=1,b=2)" when: 'get data resource request is performed' def response = mvc.perform( - get(getUrl) - .contentType(MediaType.APPLICATION_JSON) + get(getUrl) + .contentType(MediaType.APPLICATION_JSON) ).andReturn().response then: 'the NCMP data service is called with getResourceDataOperationalForCmHandle' 1 * mockNetworkCmProxyDataService.getResourceDataOperationalForCmHandle('testCmHandle', - 'parent/child', - '(a=1,b=2)', - NO_TOPIC, - NO_REQUEST_ID) + 'parent/child', + '(a=1,b=2)', + NO_TOPIC, + NO_REQUEST_ID) and: 'response status is Ok' response.status == HttpStatus.OK.value() } @@ -126,22 +154,22 @@ class NetworkCmProxyControllerSpec extends Specification { def 'Get Resource Data from #datastoreInUrl with #scenario.'() { given: 'resource data url' def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:${datastoreInUrl}" + - "?resourceIdentifier=parent/child&options=(a=1,b=2)${topicQueryParam}" + "?resourceIdentifier=parent/child&options=(a=1,b=2)${topicQueryParam}" when: 'get data resource request is performed' def response = mvc.perform( - get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response + get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response then: 'task executor is called appropriate number of times' - expectedNumberOfExecutorExecutions * spiedCpsTaskExecutor.executeTask(_, 2000) + expectedNumberOfExecutorExecutions * spiedCpsTaskExecutor.executeTask(_, TIMEOUT_IN_MS) and: 'response status is expected' response.status == HttpStatus.OK.value() where: 'the following parameters are used' - scenario | datastoreInUrl | topicQueryParam || expectedTopicName | expectedNumberOfExecutorExecutions - 'url with valid topic' | 'passthrough-operational' | '&topic=my-topic-name' || 'my-topic-name' | 1 - 'no topic in url' | 'passthrough-operational' | '' || NO_TOPIC | 0 - 'null topic in url' | 'passthrough-operational' | '&topic=null' || 'null' | 1 - 'url with valid topic' | 'passthrough-running' | '&topic=my-topic-name' || 'my-topic-name' | 1 - 'no topic in url' | 'passthrough-running' | '' || NO_TOPIC | 0 - 'null topic in url' | 'passthrough-running' | '&topic=null' || 'null' | 1 + scenario | datastoreInUrl | topicQueryParam || expectedTopicName | expectedNumberOfExecutorExecutions + 'url with valid topic' | 'passthrough-operational' | '&topic=my-topic-name' || 'my-topic-name' | 1 + 'no topic in url' | 'passthrough-operational' | '' || NO_TOPIC | 0 + 'null topic in url' | 'passthrough-operational' | '&topic=null' || 'null' | 1 + 'url with valid topic' | 'passthrough-running' | '&topic=my-topic-name' || 'my-topic-name' | 1 + 'no topic in url' | 'passthrough-running' | '' || NO_TOPIC | 0 + 'null topic in url' | 'passthrough-running' | '&topic=null' || 'null' | 1 } def 'Fail to get Resource Data from #datastoreInUrl when #scenario.'() { @@ -168,17 +196,17 @@ class NetworkCmProxyControllerSpec extends Specification { def 'Get Resource Data from pass-through running with #scenario value in resource identifier param.'() { given: 'resource data url' def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" + - "?resourceIdentifier=" + resourceIdentifier + "&options=(a=1,b=2)" + "?resourceIdentifier=" + resourceIdentifier + "&options=(a=1,b=2)" and: 'ncmp service returns json object' mockNetworkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle('testCmHandle', - resourceIdentifier, - '(a=1,b=2)', - NO_TOPIC, - NO_REQUEST_ID) >> '{valid-json}' + resourceIdentifier, + '(a=1,b=2)', + NO_TOPIC, + NO_REQUEST_ID) >> '{valid-json}' when: 'get data resource request is performed' def response = mvc.perform( - get(getUrl) - .contentType(MediaType.APPLICATION_JSON) + get(getUrl) + .contentType(MediaType.APPLICATION_JSON) ).andReturn().response then: 'response status is Ok' response.status == HttpStatus.OK.value() @@ -194,7 +222,7 @@ class NetworkCmProxyControllerSpec extends Specification { '? needs to be encoded as %3F' | 'idWith%3F' } - def 'Update resource data from pass-through running.' () { + def 'Update resource data from pass-through running.'() { given: 'update resource data url' def updateUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" + "?resourceIdentifier=parent/child" @@ -210,15 +238,15 @@ class NetworkCmProxyControllerSpec extends Specification { response.status == HttpStatus.OK.value() } - def 'Create Resource Data from pass-through running with #scenario.' () { + def 'Create Resource Data from pass-through running with #scenario.'() { given: 'resource data url' def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" + - "?resourceIdentifier=parent/child" + "?resourceIdentifier=parent/child" def requestBody = '{"some-key":"some-value"}' when: 'create resource request is performed' def response = mvc.perform( - post(url) - .contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody) + post(url) + .contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody) ).andReturn().response then: 'ncmp service method to create resource called' 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', @@ -227,14 +255,14 @@ class NetworkCmProxyControllerSpec extends Specification { response.status == HttpStatus.CREATED.value() } - def 'Get module references for the given dataspace and cm handle.' () { + def 'Get module references for the given dataspace and cm handle.'() { given: 'get module references url' def getUrl = "$ncmpBasePathV1/ch/some-cmhandle/modules" when: 'get module resource request is performed' - def response =mvc.perform(get(getUrl)).andReturn().response + def response = mvc.perform(get(getUrl)).andReturn().response then: 'ncmp service method to get yang resource module references is called' mockNetworkCmProxyDataService.getYangResourcesModuleReferences('some-cmhandle') - >> [new ModuleReference(moduleName: 'some-name1',revision: '2021-10-03')] + >> [new ModuleReference(moduleName: 'some-name1', revision: '2021-10-03')] and: 'response contains an array with the module name and revision' response.getContentAsString() == '[{"moduleName":"some-name1","revision":"2021-10-03"}]' and: 'response returns an OK http code' @@ -248,15 +276,15 @@ class NetworkCmProxyControllerSpec extends Specification { and: 'the service method is invoked with module names and returns two cm handles' def cmHandle1 = new NcmpServiceCmHandle() cmHandle1.cmHandleId = 'some-cmhandle-id1' - cmHandle1.publicProperties = [color:'yellow'] + cmHandle1.publicProperties = [color: 'yellow'] def cmHandle2 = new NcmpServiceCmHandle() cmHandle2.cmHandleId = 'some-cmhandle-id2' - cmHandle2.publicProperties = [color:'green'] + cmHandle2.publicProperties = [color: 'green'] mockNetworkCmProxyDataService.executeCmHandleSearch(_) >> [cmHandle1, cmHandle2] when: 'the searches api is invoked' def response = mvc.perform(post(searchesEndpoint) - .contentType(MediaType.APPLICATION_JSON) - .content(jsonString)).andReturn().response + .contentType(MediaType.APPLICATION_JSON) + .content(jsonString)).andReturn().response then: 'response status returns OK' response.status == HttpStatus.OK.value() and: 'the expected response content is returned' @@ -268,14 +296,15 @@ class NetworkCmProxyControllerSpec extends Specification { def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/some-cm-handle" and: 'an existing ncmp service cm handle' def cmHandleId = 'some-cm-handle' - def dmiProperties = [ prop:'some DMI property' ] - def publicProperties = [ "public prop":'some public property' ] + def dmiProperties = [prop: 'some DMI property'] + def publicProperties = ["public prop": 'some public property'] def compositeState = compositeStateTestObject() def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState) and: 'the service method is invoked with the cm handle id' 1 * mockNetworkCmProxyDataService.getNcmpServiceCmHandle('some-cm-handle') >> ncmpServiceCmHandle when: 'the cm handle details api is invoked' - def response = mvc.perform(get(cmHandleDetailsEndpoint)).andReturn().response + def response = mvc.perform( + get(cmHandleDetailsEndpoint)).andReturn().response then: 'the correct response is returned' response.status == HttpStatus.OK.value() and: 'the response contains the public properties' @@ -286,30 +315,34 @@ class NetworkCmProxyControllerSpec extends Specification { !response.contentAsString.contains("some DMI property") } - def 'Get Cm Handle public properties by Cm Handle id.' () { + def 'Get Cm Handle public properties by Cm Handle id.'() { given: 'a cm handle properties endpoint' def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle/properties" and: 'some cm handle public properties' - def publicProperties = [ 'public prop':'some public property' ] + def publicProperties = ['public prop': 'some public property'] and: 'the service method is invoked with the cm handle id returning the cm handle public properties' - 1 * mockNetworkCmProxyDataService.getCmHandlePublicProperties('some-cm-handle') >> publicProperties + 1 * mockNetworkCmProxyDataService + .getCmHandlePublicProperties('some-cm-handle') >> publicProperties when: 'the cm handle properties api is invoked' - def response = mvc.perform(get(cmHandlePropertiesEndpoint)).andReturn().response + def response = mvc.perform( + get(cmHandlePropertiesEndpoint)).andReturn().response then: 'the correct response is returned' response.status == HttpStatus.OK.value() and: 'the response contains the public properties' assertContainsPublicProperties(response) } - def 'Get Cm Handle composite state by Cm Handle id.' () { + def 'Get Cm Handle composite state by Cm Handle id.'() { given: 'a cm handle state endpoint' def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle/state" and: 'some cm handle composite state' def compositeState = compositeStateTestObject() and: 'the service method is invoked with the cm handle id returning the cm handle composite state' - 1 * mockNetworkCmProxyDataService.getCmHandleCompositeState('some-cm-handle') >> compositeState + 1 * mockNetworkCmProxyDataService + .getCmHandleCompositeState('some-cm-handle') >> compositeState when: 'the cm handle state api is invoked' - def response = mvc.perform(get(cmHandlePropertiesEndpoint)).andReturn().response + def response = mvc.perform( + get(cmHandlePropertiesEndpoint)).andReturn().response then: 'the correct response is returned' response.status == HttpStatus.OK.value() and: 'the response contains the cm handle state' @@ -323,13 +356,14 @@ class NetworkCmProxyControllerSpec extends Specification { and: 'the service method is invoked with module names and returns two cm handles' def cmHandel1 = new NcmpServiceCmHandle() cmHandel1.cmHandleId = 'some-cmhandle-id1' - cmHandel1.publicProperties = [color:'yellow'] + cmHandel1.publicProperties = [color: 'yellow'] def cmHandel2 = new NcmpServiceCmHandle() cmHandel2.cmHandleId = 'some-cmhandle-id2' - cmHandel2.publicProperties = [color:'green'] + cmHandel2.publicProperties = [color: 'green'] mockNetworkCmProxyDataService.executeCmHandleSearch(_) >> [cmHandel1, cmHandel2] when: 'the searches api is invoked' - def response = mvc.perform(post(searchesEndpoint) + def response = mvc.perform( + post(searchesEndpoint) .contentType(MediaType.APPLICATION_JSON) .content(jsonString)).andReturn().response then: 'an empty cm handle identifier is returned' @@ -342,9 +376,10 @@ class NetworkCmProxyControllerSpec extends Specification { and: 'the service method is invoked with module names and returns cm handle ids' 1 * mockNetworkCmProxyDataService.executeCmHandleIdSearch(_) >> ['some-cmhandle-id1', 'some-cmhandle-id2'] when: 'the searches api is invoked' - def response = mvc.perform(post(searchesEndpoint) - .contentType(MediaType.APPLICATION_JSON) - .content('{}')).andReturn().response + def response = mvc.perform( + post(searchesEndpoint) + .contentType(MediaType.APPLICATION_JSON) + .content('{}')).andReturn().response then: 'cm handle ids are returned' response.contentAsString == '["some-cmhandle-id1","some-cmhandle-id2"]' } @@ -353,37 +388,39 @@ class NetworkCmProxyControllerSpec extends Specification { when: 'the searches api is invoked' def searchesEndpoint = "$ncmpBasePathV1/ch/id-searches" def invalidInputData = '{invalidJson}' - def response = mvc.perform(post(searchesEndpoint) + def response = mvc.perform( + post(searchesEndpoint) .contentType(MediaType.APPLICATION_JSON) .content(invalidInputData)).andReturn().response then: 'BAD_REQUEST is returned' response.getStatus() == 400 } - def 'Patch resource data in pass-through running datastore.' () { + def 'Patch resource data in pass-through running datastore.'() { given: 'patch resource data url' def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" + - "?resourceIdentifier=parent/child" + "?resourceIdentifier=parent/child" when: 'patch data resource request is performed' def response = mvc.perform( - patch(url) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON).content(requestBody) + patch(url) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON).content(requestBody) ).andReturn().response then: 'ncmp service method to update resource is called' 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', - 'parent/child', PATCH, requestBody, 'application/json;charset=UTF-8') + 'parent/child', PATCH, requestBody, 'application/json;charset=UTF-8') and: 'the response status is OK' response.status == HttpStatus.OK.value() } - def 'Delete resource data in pass-through running datastore.' () { + def 'Delete resource data in pass-through running datastore.'() { given: 'delete resource data url' def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" + - "?resourceIdentifier=parent/child" + "?resourceIdentifier=parent/child" when: 'delete data resource request is performed' def response = mvc.perform( - delete(url).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andReturn().response + delete(url) + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andReturn().response then: 'the ncmp service method to delete resource is called (with null as body)' 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'parent/child', DELETE, null, 'application/json;charset=UTF-8') @@ -394,12 +431,12 @@ class NetworkCmProxyControllerSpec extends Specification { def 'Get resource data from DMI with valid topic i.e. async request for #scenario'() { given: 'resource data url' def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:${datastoreInUrl}" + - "?resourceIdentifier=parent/child&options=(a=1,b=2)&topic=my-topic-name" + "?resourceIdentifier=parent/child&options=(a=1,b=2)&topic=my-topic-name" when: 'get data resource request is performed' def response = mvc.perform( - get(getUrl) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON_VALUE) + get(getUrl) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON_VALUE) ).andReturn().response then: 'async request id is generated' assert response.contentAsString.contains("requestId") @@ -409,32 +446,68 @@ class NetworkCmProxyControllerSpec extends Specification { ':passthrough-running' | 'passthrough-running' } - def 'Get module definitions based on cmHandleId.' () { + def 'Get module definitions based on cmHandleId.'() { when: 'get module definition request is performed' - def response = mvc.perform(get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions")) - .andReturn().response + def response = mvc.perform( + get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions")) + .andReturn().response then: 'ncmp service method to get module definitions is called' mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle') - >> [new ModuleDefinition('sampleModuleName', '2021-10-03', - 'module sampleModuleName{ sample module content }')] + >> [new ModuleDefinition('sampleModuleName', '2021-10-03', + 'module sampleModuleName{ sample module content }')] and: 'response contains an array with the module name, revision and content' response.getContentAsString() == '[{"moduleName":"sampleModuleName","revision":"2021-10-03","content":"module sampleModuleName{ sample module content }"}]' and: 'response returns an OK http code' response.status == HttpStatus.OK.value() } - def 'Set the data sync enabled based on the cm handle id and the data sync flag is #scenario' () { + def 'Set the data sync enabled based on the cm handle id and the data sync flag is #scenario'() { when: 'the set data sync enabled request is invoked' - def response = mvc.perform(put("$ncmpBasePathV1/ch/some-cm-handle-id/data-sync?dataSyncEnabled=" + dataSyncEnabledFlag)) - .andReturn().response + def response = mvc.perform( + put("$ncmpBasePathV1/ch/some-cm-handle-id/data-sync?dataSyncEnabled=" + dataSyncEnabledFlag)) + .andReturn().response then: 'method to set data sync enabled is called' 1 * mockNetworkCmProxyDataService.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag) and: 'the response returns an OK http code' response.status == HttpStatus.OK.value() where: 'the following parameters are used' - scenario | dataSyncEnabledFlag - 'enabled' | true - 'disabled' | false + scenario | dataSyncEnabledFlag + 'enabled' | true + 'disabled' | false + } + + def 'Get Resource Data from operational without descendants.'() { + given: 'resource data url' + def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:operational" + + "?resourceIdentifier=parent/child&include-descendants=false" + when: 'get data resource request is performed' + def response = mvc.perform( + get(getUrl) + .contentType(MediaType.APPLICATION_JSON) + ).andReturn().response + then: 'the NCMP data service is called with getResourceDataOperational' + 1 * mockNetworkCmProxyDataService.getResourceDataOperational('testCmHandle', + 'parent/child', + FetchDescendantsOption.OMIT_DESCENDANTS) + and: 'response status is Ok' + response.status == HttpStatus.OK.value() + } + + def 'Get Resource Data from operational including descendants.'() { + given: 'resource data url' + def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:operational" + + "?resourceIdentifier=parent/child&include-descendants=true" + when: 'get data resource request is performed' + def response = mvc.perform( + get(getUrl) + .contentType(MediaType.APPLICATION_JSON) + ).andReturn().response + then: 'the NCMP data service is called with getResourceDataOperational' + 1 * mockNetworkCmProxyDataService.getResourceDataOperational('testCmHandle', + 'parent/child', + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + and: 'response status is Ok' + response.status == HttpStatus.OK.value() } def dataStores() { @@ -453,7 +526,7 @@ class NetworkCmProxyControllerSpec extends Specification { } def assertContainsAll(response, assertContent) { - assertContent.forEach( string -> { assert(response.contentAsString.contains(string)) }) + assertContent.forEach(string -> { assert (response.contentAsString.contains(string)) }) return void } @@ -476,8 +549,8 @@ class NetworkCmProxyControllerSpec extends Specification { def assertContainsPublicProperties(response) { def expectedContent = [ - '"publicCmHandleProperties":' , - '"public prop"' , + '"publicCmHandleProperties":', + '"public prop"', '"some public property"' ] return assertContainsAll(response, expectedContent) diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreResourceRequestHandlerFactorySpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreResourceRequestHandlerFactorySpec.groovy new file mode 100644 index 000000000..3f7a8a5ce --- /dev/null +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreResourceRequestHandlerFactorySpec.groovy @@ -0,0 +1,20 @@ +package org.onap.cps.ncmp.rest.controller.handlers + +import spock.lang.Specification + +class NcmpDatastoreResourceRequestHandlerFactorySpec extends Specification { + + def objectUnderTest = new NcmpDatastoreResourceRequestHandlerFactory(null, null) + + def 'Creating ncmp datastore request handlers.'() { + when: 'a ncmp datastore request handler is created for #datastoreType' + def result = objectUnderTest.getNcmpDatastoreResourceRequestHandler(datastoreType) + then: 'the result is of the expected class' + result.class == expectedClass + where: 'the following type of datastore is used' + datastoreType || expectedClass + DatastoreType.OPERATIONAL || NcmpDatastoreOperationalResourceRequestHandler + DatastoreType.PASSTHROUGH_OPERATIONAL || NcmpDatastorePassthroughOperationalResourceRequestHandler + DatastoreType.PASSTHROUGH_RUNNING || NcmpDatastorePassthroughRunningResourceRequestHandler + } +} \ No newline at end of file diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy index ce908e754..b8b7fe3bc 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy @@ -29,8 +29,9 @@ import org.onap.cps.ncmp.api.impl.exception.DmiRequestException import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException import org.onap.cps.ncmp.rest.controller.NcmpRestInputMapper -import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper +import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastoreResourceRequestHandlerFactory import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor +import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper import org.onap.cps.ncmp.rest.util.DeprecationHelper import org.onap.cps.spi.exceptions.CpsException import org.onap.cps.spi.exceptions.DataNodeNotFoundException @@ -48,9 +49,7 @@ import spock.lang.Specification import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMP import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMPINVENTORY -import static org.springframework.http.HttpStatus.BAD_REQUEST -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR -import static org.springframework.http.HttpStatus.NOT_FOUND +import static org.springframework.http.HttpStatus.* import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post @@ -78,6 +77,9 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification { @SpringBean DeprecationHelper stubbedDeprecationHelper = Stub() + @SpringBean + NcmpDatastoreResourceRequestHandlerFactory mockedNcmpDatastoreResourceRequestHandlerFactory = Mock() + @Value('${rest.api.ncmp-base-path}') def basePathNcmp @@ -125,7 +127,7 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification { def 'Failing DMI Request - passthrough scenario'() { given: 'failing DMI request' - setupTestException(new HttpClientRequestException('Error Message Details NCMP', 'Bad Request from DMI', 400) , NCMP) + setupTestException(new HttpClientRequestException('Error Message Details NCMP', 'Bad Request from DMI', 400), NCMP) when: 'the DMI request is executed' def response = performTestRequest(NCMP) then: 'NCMP service responds with 502 Bad Gateway status' @@ -150,7 +152,7 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification { return mvc.perform(post("$dataNodeBaseEndpointNcmpInventory/ch").contentType(MediaType.APPLICATION_JSON).content(jsonData)).andReturn().response } - static void assertTestResponse(response, expectedStatus , expectedErrorMessage , expectedErrorDetails) { + static void assertTestResponse(response, expectedStatus, expectedErrorMessage, expectedErrorDetails) { assert response.status == expectedStatus.value() def content = new JsonSlurper().parseText(response.contentAsString) assert content['status'].toString().contains(expectedStatus.toString()) diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/TopicValidatorSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/TopicValidatorSpec.groovy new file mode 100644 index 000000000..e626e1505 --- /dev/null +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/TopicValidatorSpec.groovy @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.rest.util + +import org.onap.cps.ncmp.rest.exceptions.InvalidTopicException +import spock.lang.Specification + +class TopicValidatorSpec extends Specification { + + def 'Valid topic name validation.'() { + when: 'a valid topic name is validated' + TopicValidator.validateTopicName('my-valid-topic') + then: 'no exception is thrown' + noExceptionThrown() + } + + def 'Validating invalid topic names.'() { + when: 'the invalid topic name is validated' + TopicValidator.validateTopicName(topicName) + then: 'boolean response will be returned for #scenario' + thrown(InvalidTopicException) + where: 'the following names are used' + scenario | topicName + 'empty topic' | '' + 'blank topic' | ' ' + 'invalid non empty topic' | '1_5_*_#' + } + +} -- cgit 1.2.3-korg