CDS functional changes 85/143585/3
authorPeukerL@telekom.de <PeukerL@telekom.de>
Wed, 25 Mar 2026 13:04:31 +0000 (14:04 +0100)
committerFiete Ostkamp <fiete.ostkamp@telekom.de>
Wed, 25 Mar 2026 15:07:51 +0000 (15:07 +0000)
- 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 <PeukerL@telekom.de>
12 files changed:
ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/utils/UatExecutor.kt
ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/IpAssignResolutionCapabilityTest.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/capabilities/NamingResolutionCapabilityTest.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt
ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/primary/service/BlueprintProcessorCatalogServiceImpl.kt
ms/blueprintsprocessor/modules/commons/db-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImplTest.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt
ms/blueprintsprocessor/modules/inbounds/health-api-common/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/service/EndPointExecution.kt
ms/blueprintsprocessor/modules/inbounds/health-api-common/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/healthapi/HealthCheckServiceTest.kt

index 1909d03..9070e96 100644 (file)
@@ -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)
index 7be0333..0b003dd 100644 (file)
@@ -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<BluePrintRestLibPropertyService>()
         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<BluePrintRestLibPropertyService>()
         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<BluePrintRestLibPropertyService>()
         every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService
index 4ce5df1..a3eb37d 100644 (file)
@@ -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
 
index 8c0aca4..7a885da 100644 (file)
@@ -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
 
index 1e29f01..cc7ca2a 100644 (file)
@@ -36,6 +36,8 @@ class MockBlueprintWebClientService(private var restClientProperties: RestClient
     else restClientProperties.url.split(":")[2]
     private var headers: Map<String, String>
 
+    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 {
index c45a28a..9a881d9 100755 (executable)
@@ -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)
+        }
+    }
 }
index 1e5dc28..3ec197e 100644 (file)
@@ -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<BluePrintProcessorException> {
+                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
+    }
 }
index e6b9177..2f2072a 100644 (file)
@@ -134,9 +134,10 @@ abstract class BaseBlueprintWebClientService<out E : RestClientProperties> : Blu
     protected fun performHttpCall(httpUriRequest: HttpUriRequest): WebClientResponse<String> {
         val httpResponse = httpClient().execute(httpUriRequest)
         val statusCode = httpResponse.statusLine.statusCode
+        val responseHeaders: Map<String, String> = 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<out E : RestClientProperties> : Blu
         WebClientResponse<T> {
             val httpResponse = httpClient().execute(httpUriRequest)
             val statusCode = httpResponse.statusLine.statusCode
+            val responseHeaders: Map<String, String> = 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 {
index 76d6d46..f8e1f67 100644 (file)
@@ -79,5 +79,6 @@ interface BlueprintWebClientService {
     }
 
     // TODO maybe there could be cases where we care about return headers?
-    data class WebClientResponse<T>(val status: Int, val body: T)
+    // Returning the Response headers including the status and body
+    data class WebClientResponse<T>(val status: Int, val body: T, val responseHeaders: Map<String, String> = emptyMap())
 }
index bca9dcc..5369e67 100644 (file)
@@ -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<String> {
+        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"
index cfee725..13f27f5 100644 (file)
@@ -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) {
index e3ba724..701316a 100644 (file)
@@ -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)