From: PeukerL@telekom.de Date: Wed, 25 Mar 2026 13:04:31 +0000 (+0100) Subject: CDS functional changes X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F85%2F143585%2F3;p=ccsdk%2Fcds.git CDS functional changes - added support for capturing response headers in the WebClientResponse object in the RestClient implementation - manage and update CBA local copy during workflow execution - prevent workflow execution when CBA is not present in DB and delete local CBA copy if exists - create Idfile for blueprint in deploy folder - update CBA local copy to latest version locally Issue-ID: CCSDK-4141 Change-Id: I1096581c3d55ca2bd09b254328382b21a5657df6 Signed-off-by: PeukerL@telekom.de --- diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt index 1909d0335..9070e961b 100644 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt +++ b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt @@ -214,7 +214,7 @@ open class UatExecutor( for (expectation in restExpectations) { if (expectation.request.requestType == EXCHANGE_RESOURCE) { val responses = expectation.responses - .map { response -> WebClientResponse(response.status, response.body.toString()) } + .map { response -> WebClientResponse(response.status, response.body.toString(), response.headers) } if (responses.isNotEmpty()) { doReturn(responses[0], *responses.drop(1).toTypedArray()) .whenever(restClient) @@ -231,7 +231,7 @@ open class UatExecutor( for (expectation in restExpectations) { if (expectation.request.requestType == UPLOAD_BINARY_FILE) { val responses = expectation.responses - .map { response -> WebClientResponse(response.status, response.body.toString()) } + .map { response -> WebClientResponse(response.status, response.body.toString(), response.headers) } if (responses.isNotEmpty()) { doReturn(responses[0], *responses.drop(1).toTypedArray()) .whenever(restClient) diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt index 7be03333f..0b003dd66 100644 --- a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt @@ -66,33 +66,33 @@ class ComponentRemoteAnsibleExecutorTest { every { webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") - } returns WebClientResponse(200, getJobTemplates(jtId)) + } returns WebClientResponse(200, getJobTemplates(jtId), emptyMap()) every { webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") - } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + } returns WebClientResponse(200, getJobTemplateLaunch(jtId), emptyMap()) every { webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") - } returns WebClientResponse(200, getInventory()) + } returns WebClientResponse(200, getInventory(), emptyMap()) every { webClientService.exchangeResource( "POST", "/api/v2/job_templates/$jtId/launch/", """{"inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}""" ) - } returns WebClientResponse(201, newJobTemplateLaunch(jtId, jobId)) + } returns WebClientResponse(201, newJobTemplateLaunch(jtId, jobId), emptyMap()) every { webClientService.exchangeResource("GET", "/api/v2/jobs/$jobId/", "") } returnsMany listOf( - WebClientResponse(200, getJobStatus1(jtId, jobId)), - WebClientResponse(200, getJobStatus2(jtId, jobId)), - WebClientResponse(200, getJobStatus3(jtId, jobId)), - WebClientResponse(200, getJobStatus4(jtId, jobId)) + WebClientResponse(200, getJobStatus1(jtId, jobId), emptyMap()), + WebClientResponse(200, getJobStatus2(jtId, jobId), emptyMap()), + WebClientResponse(200, getJobStatus3(jtId, jobId), emptyMap()), + WebClientResponse(200, getJobStatus4(jtId, jobId), emptyMap()) ) every { webClientService.exchangeResource( "GET", "/api/v2/jobs/$jobId/stdout/?format=txt", "", mapOf("Accept" to "text/plain") ) - } returns WebClientResponse(200, getReport()) + } returns WebClientResponse(200, getReport(), emptyMap()) val selector = mapper.readTree(endpointSelector) val bluePrintRestLibPropertyService = mockk() every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService @@ -120,13 +120,13 @@ class ComponentRemoteAnsibleExecutorTest { every { webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") - } returns WebClientResponse(200, getJobTemplates(jtId)) + } returns WebClientResponse(200, getJobTemplates(jtId), emptyMap()) every { webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") - } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + } returns WebClientResponse(200, getJobTemplateLaunch(jtId), emptyMap()) every { webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") - } returns WebClientResponse(404, "") + } returns WebClientResponse(404, "", emptyMap()) val selector = mapper.readTree(endpointSelector) val bluePrintRestLibPropertyService = mockk() every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService @@ -155,19 +155,19 @@ class ComponentRemoteAnsibleExecutorTest { every { webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") - } returns WebClientResponse(200, getJobTemplates(jtId)) + } returns WebClientResponse(200, getJobTemplates(jtId), emptyMap()) every { webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") - } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + } returns WebClientResponse(200, getJobTemplateLaunch(jtId), emptyMap()) every { webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") - } returns WebClientResponse(200, getInventory()) + } returns WebClientResponse(200, getInventory(), emptyMap()) every { webClientService.exchangeResource( "POST", "/api/v2/job_templates/$jtId/launch/", """{"limit":"123","tags":"some-tag","skip_tags":"some-skip-tag","inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}""" ) - } returns WebClientResponse(500, "") + } returns WebClientResponse(500, "", emptyMap()) val selector = mapper.readTree(endpointSelector) val bluePrintRestLibPropertyService = mockk() every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/IpAssignResolutionCapabilityTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/IpAssignResolutionCapabilityTest.kt index 4ce5df18f..a3eb37d87 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/IpAssignResolutionCapabilityTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/IpAssignResolutionCapabilityTest.kt @@ -68,7 +68,8 @@ class IpAssignResolutionCapabilityTest { "fixed_ipv4_Address_02" : "10.10.10.12", "fixed_ipv4_Address_03" : "10.10.10.13" } - """.trimMargin() + """.trimMargin(), + emptyMap() ) every { blueprintWebClientService.exchangeResource(any(), any(), any()) } returns mockResponse diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/NamingResolutionCapabilityTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/NamingResolutionCapabilityTest.kt index 8c0aca49e..7a885da2e 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/NamingResolutionCapabilityTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/NamingResolutionCapabilityTest.kt @@ -70,7 +70,8 @@ class NamingResolutionCapabilityTest { "vf-module-name" : "dlsst001dbcx-adsf-Base-01", "vnfc-name" : "dlsst001dbcx" } - """.trimMargin() + """.trimMargin(), + emptyMap() ) every { blueprintWebClientService.exchangeResource(any(), any(), any()) } returns mockResponse diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt index 1e29f01cc..cc7ca2ac1 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt @@ -36,6 +36,8 @@ class MockBlueprintWebClientService(private var restClientProperties: RestClient else restClientProperties.url.split(":")[2] private var headers: Map + private val contentTypeResponseHeader = Header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + companion object { const val JSON_OUTPUT: String = "{" + "\"vnf-id\":\"123456\"," + @@ -119,7 +121,7 @@ class MockBlueprintWebClientService(private var restClientProperties: RestClient request().withHeaders(Header(HttpHeaders.AUTHORIZATION, headers[HttpHeaders.AUTHORIZATION])) .withMethod(method) .withPath(path) - ).respond(response().withStatusCode(200).withBody(requestResponse)) + ).respond(response().withStatusCode(200).withBody(requestResponse).withHeader(contentTypeResponseHeader)) } private fun setRequestWithPayload(method: String, path: String, payload: String) { @@ -142,7 +144,7 @@ class MockBlueprintWebClientService(private var restClientProperties: RestClient .withPath(path) .withQueryStringParameter("format", "resource") .withBody(payload) - ).respond(response().withStatusCode(200).withBody(requestResponse)) + ).respond(response().withStatusCode(200).withBody(requestResponse).withHeaders(contentTypeResponseHeader)) } private fun setBasicAuth(username: String, password: String): String { diff --git a/ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/primary/service/BlueprintProcessorCatalogServiceImpl.kt b/ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/primary/service/BlueprintProcessorCatalogServiceImpl.kt index c45a28a07..9a881d903 100755 --- a/ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/primary/service/BlueprintProcessorCatalogServiceImpl.kt +++ b/ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/primary/service/BlueprintProcessorCatalogServiceImpl.kt @@ -18,6 +18,8 @@ package org.onap.ccsdk.cds.blueprintsprocessor.db.primary.service +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.onap.ccsdk.cds.blueprintsprocessor.core.cluster.BlueprintClusterTopic import org.onap.ccsdk.cds.blueprintsprocessor.core.cluster.optionalClusterService import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModel @@ -83,35 +85,38 @@ class BlueprintProcessorCatalogServiceImpl( UUID.randomUUID().toString(), "cba.zip" ) + log.info("getting blueprint Id using name($name), version($version) from db") + val blueprintId = try { + withContext(Dispatchers.IO) { + blueprintModelRepository.findIdByArtifactNameAndArtifactVersion(name, version) + ?: throw BluePrintProcessorException("Blueprint does not exist in DB") + } + } catch (e: Exception) { + if (deployFile.exists()) { + deleteNBDir(deployFile.absolutePath) + } + throw BluePrintProcessorException( + "failed to get cba file name($name), version($version) from db" + + " : ${e.message}" + ) + } + if (extract && deployFile.exists()) { + /** Check and update if the different idFile exists **/ + val idFileExists: Boolean = withContext(Dispatchers.IO) { + deployFile + .listFiles() + ?.any { it.isFile && it.name == blueprintId } + ?: false + } + if (!idFileExists) { + log.info("update (${deployFile.absolutePath}) folder with the current version") + updateDeployFolder(name, version, cbaFile, deployFile) + } log.info("cba file name($name), version($version) already present(${deployFile.absolutePath})") } else { - deployFile.reCreateNBDirs() - cbaFile.parentFile.reCreateNBDirs() - - try { - log.info("getting cba file name($name), version($version) from db") - blueprintModelRepository.findByArtifactNameAndArtifactVersion(name, version)?.also { - it.blueprintModelContent.run { - - cbaFile.writeBytes(this!!.content!!) - cbaFile.deCompress(deployFile) - log.info("cba file name($name), version($version) saved in (${deployFile.absolutePath})") - } - } - - check(deployFile.exists() && deployFile.list().isNotEmpty()) { - throw BluePrintProcessorException("file check failed") - } - } catch (e: Exception) { - deleteNBDir(deployFile.absolutePath) - throw BluePrintProcessorException( - "failed to get get cba file name($name), version($version) from db" + - " : ${e.message}" - ) - } finally { - deleteNBDir(cbaFile.parentFile.absolutePath) - } + log.info("creating cba file of name($name), version($version) in (${deployFile.absolutePath})") + updateDeployFolder(name, version, cbaFile, deployFile) } return if (extract) { @@ -185,4 +190,38 @@ class BlueprintProcessorCatalogServiceImpl( clusterService.sendMessage(BlueprintClusterTopic.BLUEPRINT_CLEAN_COMPILER_CACHE, cacheKey) } else BluePrintCompileCache.cleanClassLoader(cacheKey) } + + private suspend fun updateDeployFolder(name: String, version: String, cbaFile: File, deployFile: File) { + deployFile.reCreateNBDirs() + cbaFile.parentFile.reCreateNBDirs() + + try { + withContext(Dispatchers.IO) { + blueprintModelRepository.findByArtifactNameAndArtifactVersion(name, version) + }?.also { + it.blueprintModelContent.run { + cbaFile.writeBytes(this!!.content!!) + cbaFile.deCompress(deployFile) + /** Add a new file using Id **/ + val idFile = File(deployFile, it.id.toString()) + withContext(Dispatchers.IO) { + idFile.createNewFile() + } + log.info("cba file name($name), version($version) saved in (${deployFile.absolutePath})") + } + } + + check(deployFile.exists() && deployFile.list().isNotEmpty()) { + throw BluePrintProcessorException("file check failed") + } + } catch (e: Exception) { + deleteNBDir(deployFile.absolutePath) + throw BluePrintProcessorException( + "failed to update cba file name($name), version($version) in deploy folder" + + " : ${e.message}" + ) + } finally { + deleteNBDir(cbaFile.parentFile.absolutePath) + } + } } diff --git a/ms/blueprintsprocessor/modules/commons/db-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImplTest.kt b/ms/blueprintsprocessor/modules/commons/db-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImplTest.kt index 1e5dc283c..3ec197e27 100644 --- a/ms/blueprintsprocessor/modules/commons/db-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImplTest.kt +++ b/ms/blueprintsprocessor/modules/commons/db-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImplTest.kt @@ -25,9 +25,12 @@ import org.onap.ccsdk.cds.blueprintsprocessor.db.mock.MockBlueprintProcessorCata import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.service.BlueprintCatalogServiceImpl import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.service.BlueprintProcessorCatalogServiceImpl import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.compress +import org.onap.ccsdk.cds.controllerblueprints.core.deCompress import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile +import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPath import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.springframework.beans.factory.annotation.Autowired @@ -37,8 +40,14 @@ import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner import java.io.File +import java.nio.file.Files +import java.nio.file.Path import kotlin.test.AfterTest import kotlin.test.BeforeTest +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertNotNull import kotlin.test.assertTrue @RunWith(SpringRunner::class) @@ -152,10 +161,110 @@ class BlueprintProcessorCatalogServiceImplTest { } } + @Test + fun `test get function creates idFile in deploy folder`() { + runBlocking { + val file = normalizedFile("./target/blueprints/generated-cba.zip") + assertTrue(file.exists(), "couldn't get file ${file.absolutePath}") + + val ctx = bluePrintRuntimeService.bluePrintContext() + val metadata = ctx.metadata!! + metadata[BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID] = blueprintId + + blueprintsProcessorCatalogService.save(metadata, file, ctx.workflows()!!) + val deployPath = blueprintsProcessorCatalogService.get("baseconfiguration", "1.0.0", true) + + assertNotNull(deployPath) + + val expectedIdFile = deployPath.resolve(blueprintId) + assertTrue( + Files.exists(expectedIdFile), + "Id file does not exists in deploy folder" + ) + } + } + + @Test + fun `test get function when blueprint doesn't exist in DB`() { + runBlocking { + val ex = assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + blueprintsProcessorCatalogService.get("baseconfiguration", "1.0.0", true) + } + assertEquals( + ex.message?.contains("Blueprint does not exist in DB"), + true, + "Exception message should indicate that the blueprint does not exist in DB." + ) + } + } + + @Test + fun `test get function to delete the cba local copy when not present in DB`() { + runBlocking { + + val file = normalizedFile("./target/blueprints/generated-cba.zip") + assertTrue(file.exists(), "couldn't get file ${file.absolutePath}") + + val tempCbaDeployFolderPath = createTempCBAInDeployFolder(file, "test_baseconfiguration", "1.0.0") + + assertTrue(Files.exists(tempCbaDeployFolderPath), "couldn't get path $tempCbaDeployFolderPath") + + assertFailsWith { + blueprintsProcessorCatalogService.get("test_baseconfiguration", "1.0.0", true) + } + + assertFalse( + Files.exists(tempCbaDeployFolderPath), + "Existing deploy folder should be deleted if CBA is not present in DB" + ) + } + } + + @Test + fun `test get function to update the cba local copy with latest version`() { + runBlocking { + val file = normalizedFile("./target/blueprints/generated-cba.zip") + assertTrue(file.exists(), "couldn't get file ${file.absolutePath}") + + val ctx = bluePrintRuntimeService.bluePrintContext() + val metadata = ctx.metadata!! + + metadata[BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID] = blueprintId + + blueprintsProcessorCatalogService.save(metadata, file, ctx.workflows()!!) + + createTempCBAInDeployFolder(file, "baseconfiguration", "1.0.0") + + val deployPath = blueprintsProcessorCatalogService.get("baseconfiguration", "1.0.0", true) + + assertNotNull(deployPath) + + val expectedIdFile = deployPath.resolve(blueprintId) + assertTrue( + Files.exists(expectedIdFile), + "Updated Id file does not exists in deploy folder" + ) + } + } + @Test fun `test delete function`() { runBlocking { blueprintsProcessorCatalogService.delete("baseconfiguration", "1.0.0") } } + + private fun createTempCBAInDeployFolder(file: File, name: String, version: String): Path { + val tempCbaDeployFolderPath = normalizedPath(blueprintCoreConfiguration.bluePrintLoadConfiguration().blueprintDeployPath, "/$name/$version") + val tempBlueprintId = "4321" + + Files.createDirectories(tempCbaDeployFolderPath) + + file.deCompress(tempCbaDeployFolderPath.toString()) + + val tempIdFilePath = tempCbaDeployFolderPath.resolve(tempBlueprintId) + Files.createFile(tempIdFilePath) + + return tempCbaDeployFolderPath + } } diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt index e6b9177e8..2f2072ad5 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt @@ -134,9 +134,10 @@ abstract class BaseBlueprintWebClientService : Blu protected fun performHttpCall(httpUriRequest: HttpUriRequest): WebClientResponse { val httpResponse = httpClient().execute(httpUriRequest) val statusCode = httpResponse.statusLine.statusCode + val responseHeaders: Map = httpResponse.allHeaders.associate { header -> header.name to header.value } httpResponse.entity.content.use { val body = IOUtils.toString(it, Charset.defaultCharset()) - return WebClientResponse(statusCode, body) + return WebClientResponse(statusCode, body, responseHeaders) } } @@ -211,16 +212,17 @@ abstract class BaseBlueprintWebClientService : Blu WebClientResponse { val httpResponse = httpClient().execute(httpUriRequest) val statusCode = httpResponse.statusLine.statusCode + val responseHeaders: Map = httpResponse.allHeaders.associate { header -> header.name to header.value } val entity: HttpEntity? = httpResponse.entity if (canResponseHaveBody(httpResponse)) { entity!!.content.use { val body = getResponse(it, responseType) - return WebClientResponse(statusCode, body) + return WebClientResponse(statusCode, body, responseHeaders) } } else { val constructor = responseType.getConstructor() val body = constructor.newInstance() - return WebClientResponse(statusCode, body) + return WebClientResponse(statusCode, body, responseHeaders) } } fun canResponseHaveBody(response: HttpResponse): Boolean { diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt index 76d6d4646..f8e1f6767 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt @@ -79,5 +79,6 @@ interface BlueprintWebClientService { } // TODO maybe there could be cases where we care about return headers? - data class WebClientResponse(val status: Int, val body: T) + // Returning the Response headers including the status and body + data class WebClientResponse(val status: Int, val body: T, val responseHeaders: Map = emptyMap()) } diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt index bca9dcc22..5369e675c 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt @@ -38,6 +38,7 @@ import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory import org.springframework.boot.web.server.WebServer import org.springframework.context.annotation.Bean +import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity @@ -133,6 +134,20 @@ class RestClientServiceTest { ) } + @Test + fun testResponseWithResponseHeaders() { + val restClientService = bluePrintRestLibPropertyService + .blueprintWebClientService("sample") + val response = restClientService.exchangeResource( + HttpMethod.GET.name(), "/sample/queryWithResponseHeaders?id=3", "" + ) + assertEquals( + "query with id:3", response.body, + "failed to get query param response" + ) + assertEquals("sample-value", response.responseHeaders["X-Test-Header"]) + } + @Test fun testPatch() { val restClientService = bluePrintRestLibPropertyService @@ -349,6 +364,14 @@ open class SampleController { fun getQuery(@RequestParam("id") id: String): String = "query with id:$id" + @GetMapping("/queryWithResponseHeaders") + fun getQueryWithResponseHeaders(@RequestParam("id") id: String): ResponseEntity { + val responseHeaders = HttpHeaders().apply { + setAll(mapOf("X-Test-Header" to "sample-value")) + } + return ResponseEntity("query with id:$id", responseHeaders, HttpStatus.OK) + } + @GetMapping("/path/{id}/get") fun getPathParam(@PathVariable("id") id: String): String = "path param id:$id" diff --git a/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/service/EndPointExecution.kt b/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/service/EndPointExecution.kt index cfee72507..13f27f53e 100644 --- a/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/service/EndPointExecution.kt +++ b/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/service/EndPointExecution.kt @@ -50,7 +50,7 @@ open class EndPointExecution( } catch (e: Exception) { logger.error("service name ${serviceEndpoint.serviceName} is down ${e.message}") } - return WebClientEnpointResponse(BlueprintWebClientService.WebClientResponse(500, "")) + return WebClientEnpointResponse(BlueprintWebClientService.WebClientResponse(500, "", emptyMap())) } private fun addClientPropertiesConfiguration(serviceEndpoint: ServiceEndpoint) { diff --git a/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/HealthCheckServiceTest.kt b/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/HealthCheckServiceTest.kt index e3ba72428..701316a70 100644 --- a/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/HealthCheckServiceTest.kt +++ b/ms/blueprintsprocessor/modules/inbounds/health-api-common/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/HealthCheckServiceTest.kt @@ -97,7 +97,7 @@ class HealthCheckServiceTest { anyString(), anyString() ) - ).thenReturn(BlueprintWebClientService.WebClientResponse(200, "Success")) + ).thenReturn(BlueprintWebClientService.WebClientResponse(200, "Success", emptyMap())) val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus() assertNotNull(healthApiResponse) assertEquals(HealthCheckStatus.UP, healthApiResponse.status) @@ -115,7 +115,7 @@ class HealthCheckServiceTest { anyString(), anyString() ) - ).thenReturn(BlueprintWebClientService.WebClientResponse(404, "failure")) + ).thenReturn(BlueprintWebClientService.WebClientResponse(404, "failure", emptyMap())) val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus() assertNotNull(healthApiResponse) assertEquals(HealthCheckStatus.DOWN, healthApiResponse.status) @@ -134,7 +134,7 @@ class HealthCheckServiceTest { anyString() ) ) - .thenReturn(BlueprintWebClientService.WebClientResponse(500, "failure")) + .thenReturn(BlueprintWebClientService.WebClientResponse(500, "failure", emptyMap())) val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus() assertNotNull(healthApiResponse) assertEquals(HealthCheckStatus.DOWN, healthApiResponse.status) @@ -154,7 +154,7 @@ class HealthCheckServiceTest { anyString() ) ) - .thenReturn(BlueprintWebClientService.WebClientResponse(300, "failure")) + .thenReturn(BlueprintWebClientService.WebClientResponse(300, "failure", emptyMap())) val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus() assertNotNull(healthApiResponse) assertEquals(HealthCheckStatus.DOWN, healthApiResponse.status)