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)
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)
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
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
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
"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
"vf-module-name" : "dlsst001dbcx-adsf-Base-01",
"vnfc-name" : "dlsst001dbcx"
}
- """.trimMargin()
+ """.trimMargin(),
+ emptyMap()
)
every { blueprintWebClientService.exchangeResource(any(), any(), any()) } returns mockResponse
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\"," +
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) {
.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 {
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
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) {
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)
+ }
+ }
}
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
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)
}
}
+ @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
+ }
}
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)
}
}
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 {
}
// 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())
}
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
)
}
+ @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
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"
} 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) {
anyString(),
anyString()
)
- ).thenReturn(BlueprintWebClientService.WebClientResponse(200, "Success"))
+ ).thenReturn(BlueprintWebClientService.WebClientResponse(200, "Success", emptyMap()))
val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus()
assertNotNull(healthApiResponse)
assertEquals(HealthCheckStatus.UP, healthApiResponse.status)
anyString(),
anyString()
)
- ).thenReturn(BlueprintWebClientService.WebClientResponse(404, "failure"))
+ ).thenReturn(BlueprintWebClientService.WebClientResponse(404, "failure", emptyMap()))
val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus()
assertNotNull(healthApiResponse)
assertEquals(HealthCheckStatus.DOWN, healthApiResponse.status)
anyString()
)
)
- .thenReturn(BlueprintWebClientService.WebClientResponse(500, "failure"))
+ .thenReturn(BlueprintWebClientService.WebClientResponse(500, "failure", emptyMap()))
val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus()
assertNotNull(healthApiResponse)
assertEquals(HealthCheckStatus.DOWN, healthApiResponse.status)
anyString()
)
)
- .thenReturn(BlueprintWebClientService.WebClientResponse(300, "failure"))
+ .thenReturn(BlueprintWebClientService.WebClientResponse(300, "failure", emptyMap()))
val healthApiResponse = bluePrintProcessorHealthCheck!!.retrieveEndpointExecutionStatus()
assertNotNull(healthApiResponse)
assertEquals(HealthCheckStatus.DOWN, healthApiResponse.status)