diff options
Diffstat (limited to 'src/test/groovy')
4 files changed, 169 insertions, 11 deletions
diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/datajobs/rest/controller/DmiDatajobsRestControllerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/datajobs/rest/controller/DmiDatajobsRestControllerSpec.groovy new file mode 100644 index 00000000..c55f53c1 --- /dev/null +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/datajobs/rest/controller/DmiDatajobsRestControllerSpec.groovy @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.dmi.datajobs.rest.controller + +import org.onap.cps.ncmp.dmi.config.WebSecurityConfig +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.context.annotation.Import +import org.springframework.http.HttpStatus +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.web.servlet.MockMvc +import spock.lang.Specification + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post + +@Import(WebSecurityConfig) +@WebMvcTest(DmiDatajobsRestController.class) +@WithMockUser +class DmiDatajobsRestControllerSpec extends Specification{ + + @Autowired + private MockMvc mvc + + @Value('${rest.api.dmi-base-path}/v1') + def basePathV1 + + def 'write request should return 501 HTTP Status' () { + given: 'URL to write a data job' + def getModuleUrl = "${basePathV1}/writeJob/001" + when: 'the request is posted' + def response = mvc.perform( + post(getModuleUrl) + .contentType('application/3gpp-json-patch+json') + ).andReturn().response + then: 'response value is Not Implemented' + response.status == HttpStatus.NOT_IMPLEMENTED.value() + } + + def 'read request should return 501 HTTP Status' () { + given: 'URL to write a data job' + def getModuleUrl = "${basePathV1}/readJob/001" + when: 'the request is posted' + def response = mvc.perform( + post(getModuleUrl) + .contentType('application/3gpp-json-patch+json') + ).andReturn().response + then: 'response value is Not Implemented' + response.status == HttpStatus.NOT_IMPLEMENTED.value() + } +} diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/async/AsyncTaskExecutorIntegrationSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/async/AsyncTaskExecutorIntegrationSpec.groovy index 7ca2d54c..12ca05cf 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/async/AsyncTaskExecutorIntegrationSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/async/AsyncTaskExecutorIntegrationSpec.groovy @@ -23,6 +23,7 @@ package org.onap.cps.ncmp.dmi.notifications.async import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.dmi.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.dmi.exception.HttpClientRequestException +import org.onap.cps.ncmp.dmi.model.DataAccessRequest import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent import org.spockframework.spring.SpringBean import org.springframework.boot.test.context.SpringBootTest @@ -31,6 +32,7 @@ import org.springframework.test.annotation.DirtiesContext import org.testcontainers.spock.Testcontainers import java.time.Duration +import java.util.function.Supplier @SpringBootTest(classes = [AsyncTaskExecutor, DmiAsyncRequestResponseEventProducer]) @Testcontainers @@ -42,6 +44,7 @@ class AsyncTaskExecutorIntegrationSpec extends MessagingBaseSpec { new DmiAsyncRequestResponseEventProducer(kafkaTemplate) def spiedObjectMapper = Spy(ObjectMapper) + def mockSupplier = Mock(Supplier) def objectUnderTest = new AsyncTaskExecutor(cpsAsyncRequestResponseEventProducer) @@ -83,4 +86,25 @@ class AsyncTaskExecutorIntegrationSpec extends MessagingBaseSpec { assert event.getEventContent().getResponseCode() == '500' } + def 'Execute an Async Task using asyncTaskExecutor and throw an error'() { + given: 'A task to be executed' + def requestId = '123456' + def operationEnum = DataAccessRequest.OperationEnum.CREATE + def timeOut = 100 + when: 'AsyncTask has been executed' + objectUnderTest.executeAsyncTask(taskSupplierForFailingTask(), TEST_TOPIC, requestId, operationEnum, timeOut) + def records = kafkaConsumer.poll(Duration.ofMillis(1500)) + then: 'the record received is the event sent' + def record = records.iterator().next() + DmiAsyncRequestResponseEvent event = spiedObjectMapper.readValue(record.value(), DmiAsyncRequestResponseEvent) + and: 'the status & code matches expected' + assert event.getEventContent().getResponseStatus() == 'Internal Server Error' + assert event.getEventContent().getResponseCode() == '500' + + } + + def taskSupplierForFailingTask() { + return () -> { throw new RuntimeException('original exception message') } + } + }
\ No newline at end of file diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/cmsubscription/CmNotificationSubscriptionDmiInEventConsumerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/cmsubscription/CmNotificationSubscriptionDmiInEventConsumerSpec.groovy index 47953439..f1f476f6 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/cmsubscription/CmNotificationSubscriptionDmiInEventConsumerSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/cmsubscription/CmNotificationSubscriptionDmiInEventConsumerSpec.groovy @@ -47,12 +47,12 @@ import java.time.OffsetDateTime import java.time.ZoneId -@SpringBootTest(classes = [CmNotificationSubscriptionDmiInEventConsumer]) @Testcontainers @DirtiesContext class CmNotificationSubscriptionDmiInEventConsumerSpec extends MessagingBaseSpec { def objectMapper = new ObjectMapper() def testTopic = 'dmi-ncmp-cm-avc-subscription' + def testDmiName = 'test-ncmp-dmi' @SpringBean CmNotificationSubscriptionDmiInEventConsumer objectUnderTest = new CmNotificationSubscriptionDmiInEventConsumer(cloudEventKafkaTemplate) @@ -70,36 +70,41 @@ class CmNotificationSubscriptionDmiInEventConsumerSpec extends MessagingBaseSpec def 'Sends subscription cloud event response successfully.'() { given: 'an subscription event response' - objectUnderTest.dmiName = 'test-ncmp-dmi' - objectUnderTest.cmNotificationSubscriptionResponseTopic = testTopic + objectUnderTest.dmiName = testDmiName + objectUnderTest.cmNotificationSubscriptionDmiOutTopic = testTopic def correlationId = 'test-subscriptionId#test-ncmp-dmi' - def cmSubscriptionDmiOutEventData = new Data(statusCode: '1', statusMessage: 'ACCEPTED') + def cmSubscriptionDmiOutEventData = new Data(statusCode: subscriptionStatusCode, statusMessage: subscriptionStatusMessage) def subscriptionEventResponse = new CmNotificationSubscriptionDmiOutEvent().withData(cmSubscriptionDmiOutEventData) and: 'consumer has a subscription' kafkaConsumer.subscribe([testTopic] as List<String>) when: 'an event is published' def eventKey = UUID.randomUUID().toString() - objectUnderTest.createAndSendCmNotificationSubscriptionDmiOutEvent(eventKey, "subscriptionCreatedStatus", correlationId, CmNotificationSubscriptionStatus.ACCEPTED) + objectUnderTest.createAndSendCmNotificationSubscriptionDmiOutEvent(eventKey, "subscriptionCreatedStatus", correlationId, subscriptionAcceptanceType) and: 'topic is polled' def records = kafkaConsumer.poll(Duration.ofMillis(1500)) - then: 'poll returns one record' + then: 'poll returns one record and close kafkaConsumer' assert records.size() == 1 def record = records.iterator().next() + kafkaConsumer.close() and: 'the record value matches the expected event value' def expectedValue = objectMapper.writeValueAsString(subscriptionEventResponse) assert expectedValue == record.value assert eventKey == record.key + where: 'given #scenario' + scenario | subscriptionAcceptanceType | subscriptionStatusCode | subscriptionStatusMessage + 'Subscription is Accepted' | CmNotificationSubscriptionStatus.ACCEPTED | '1' | 'ACCEPTED' + 'Subscription is Rejected' | CmNotificationSubscriptionStatus.REJECTED | '104' | 'REJECTED' } def 'Consume valid message.'() { given: 'an event' - objectUnderTest.dmiName = 'test-ncmp-dmi' + objectUnderTest.dmiName = testDmiName def eventKey = UUID.randomUUID().toString() def timestamp = new Timestamp(1679521929511) def jsonData = TestUtils.getResourceFileContent('cmNotificationSubscriptionCreationEvent.json') def subscriptionEvent = objectMapper.readValue(jsonData, CmNotificationSubscriptionDmiInEvent.class) - objectUnderTest.cmNotificationSubscriptionResponseTopic = testTopic + objectUnderTest.cmNotificationSubscriptionDmiOutTopic = testTopic def cloudEvent = CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withSource(URI.create('test-ncmp-dmi')) .withType(subscriptionType) .withDataSchema(URI.create("urn:cps:" + CmNotificationSubscriptionDmiInEvent.class.getName() + ":1.0.0")) @@ -119,11 +124,11 @@ class CmNotificationSubscriptionDmiInEventConsumerSpec extends MessagingBaseSpec def 'Consume invalid message.'() { given: 'an invalid event body' - objectUnderTest.dmiName = 'test-ncmp-dmi' + objectUnderTest.dmiName = testDmiName def eventKey = UUID.randomUUID().toString() def timestamp = new Timestamp(1679521929511) def invalidJsonBody = "/////" - objectUnderTest.cmNotificationSubscriptionResponseTopic = testTopic + objectUnderTest.cmNotificationSubscriptionDmiOutTopic = testTopic def cloudEvent = CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withSource(URI.create('test-ncmp-dmi')) .withType("subscriptionCreated") .withDataSchema(URI.create("urn:cps:org.onap.ncmp.dmi.cm.subscription:1.0.0")) diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy index 7b2570b0..a519de7b 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy @@ -21,6 +21,10 @@ package org.onap.cps.ncmp.dmi.rest.controller + +import ch.qos.logback.classic.Logger +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.read.ListAppender import org.onap.cps.ncmp.dmi.TestUtils import org.onap.cps.ncmp.dmi.config.WebSecurityConfig import org.onap.cps.ncmp.dmi.exception.DmiException @@ -34,6 +38,7 @@ import org.onap.cps.ncmp.dmi.notifications.async.AsyncTaskExecutor import org.onap.cps.ncmp.dmi.notifications.async.DmiAsyncRequestResponseEventProducer import org.onap.cps.ncmp.dmi.service.DmiService import org.onap.cps.ncmp.dmi.service.model.ModuleReference +import org.slf4j.LoggerFactory import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value @@ -75,6 +80,17 @@ class DmiRestControllerSpec extends Specification { @SpringBean AsyncTaskExecutor asyncTaskExecutor = new AsyncTaskExecutor(cpsAsyncRequestResponseEventProducer) + def logger = Spy(ListAppender<ILoggingEvent>) + + void setup() { + ((Logger) LoggerFactory.getLogger(DmiRestController.class)).addAppender(logger) + logger.start() + } + + void cleanup() { + ((Logger) LoggerFactory.getLogger(DmiRestController.class)).detachAndStopAllAppenders() + } + @Value('${rest.api.dmi-base-path}/v1') def basePathV1 @@ -189,6 +205,26 @@ class DmiRestControllerSpec extends Specification { response.status == HttpStatus.NOT_FOUND.value() } + def 'Retrieve module resources and ensure module set tag is logged.'() { + given: 'URL to get module resources' + def getModulesEndpoint = "$basePathV1/ch/some-cm-handle/moduleResources" + and: 'request data to get some modules' + String jsonData = TestUtils.getResourceFileContent('moduleResources.json') + and: 'the DMI service returns the yang resources' + def moduleReferences = [] + def yangResources = new YangResources() + def yangResource = new YangResource() + yangResources.add(yangResource) + mockDmiService.getModuleResources('some-cm-handle', moduleReferences) >> yangResources + when: 'the request is posted' + mvc.perform(post(getModulesEndpoint) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonData)) + then: 'the module set tag is logged' + def loggingMessage = getLoggingMessage(0) + assert loggingMessage.contains('module-set-tag1') + } + def 'Get resource data for pass-through operational.'() { given: 'Get resource data url and some request data' def getResourceDataForCmHandleUrl = "${basePathV1}/ch/some-cmHandle/data/ds/ncmp-datastore:passthrough-operational" + @@ -302,6 +338,19 @@ class DmiRestControllerSpec extends Specification { resourceIdentifier << ['passthrough-operational', 'passthrough-running'] } + def 'PassThrough logs module set tag'(){ + given: 'Passthrough read URL and request data with a module set tag (parameter)' + def readPassThroughUrl ="${basePathV1}/ch/some-cmHandle/data/ds/ncmp-datastore:" + + 'passthrough-running?resourceIdentifier=some-resourceIdentifier' + def jsonData = TestUtils.getResourceFileContent('readData.json') + when: 'the request is posted' + mvc.perform( + post(readPassThroughUrl).contentType(MediaType.APPLICATION_JSON).content(jsonData)) + then: 'response status is OK' + def loggingMessage = getLoggingMessage(0) + assert loggingMessage.contains('module-set-tag-example') + } + def 'Get resource data for pass-through running with #scenario value in resource identifier param.'() { given: 'Get resource data url' def getResourceDataForCmHandleUrl = "${basePathV1}/ch/some-cmHandle/data/ds/ncmp-datastore:passthrough-running" + @@ -335,12 +384,23 @@ class DmiRestControllerSpec extends Specification { def resourceDataUrl = "$basePathV1/data?topic=client-topic-name&requestId=some-requestId" and: 'list of operation details are received into request body' def dataOperationRequestBody = '[{"operation": "read", "operationId": "14", "datastore": "ncmp-datastore:passthrough-operational", "options": "some options", "resourceIdentifier": "some resourceIdentifier",' + - ' "cmhandles": [ {"id": "cmHanlde123", "cmHandleProperties": { "myProp`": "some value", "otherProp": "other value"}}]}]' + '"cmHandles": [ {"id": "cmHandle123", "moduleSetTag": "module-set-tag1", "cmHandleProperties": { "myProp`": "some value", "otherProp": "other value"}}]}]' when: 'the dmi resource data for dataOperation api is called.' def response = mvc.perform( post(resourceDataUrl).contentType(MediaType.APPLICATION_JSON).content(dataOperationRequestBody) ).andReturn().response then: 'the resource data operation endpoint returns the not implemented response' assert response.status == 501 + and: 'the job details are correctly received (logged)' + assert getLoggingMessage(1).contains('some-requestId') + assert getLoggingMessage(2).contains('client-topic-name') + assert getLoggingMessage(4).contains('some resourceIdentifier') + assert getLoggingMessage(5).contains('module-set-tag1') + and: 'the operation Id is correctly received (logged)' + assert getLoggingMessage(6).contains('14') + } + + def getLoggingMessage(int index) { + return logger.list[index].formattedMessage } }
\ No newline at end of file |