Http 204 response results with exception in rest resolution 73/130473/6
authorFrank Kimmlingen <frank.kimmlingen@telekom.de>
Mon, 29 Aug 2022 11:28:01 +0000 (13:28 +0200)
committerJozsef Csongvai <jozsef.csongvai@bell.ca>
Thu, 1 Sep 2022 14:20:03 +0000 (14:20 +0000)
Issue-ID: CCSDK-3746
Signed-off-by: Frank Kimmlingen <frank.kimmlingen@telekom.de>
Change-Id: I740c970de631e58902e6f92b9069aee8d3ae075b

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/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt

index bc1dc4e..ccc2f92 100644 (file)
@@ -23,6 +23,9 @@ import com.fasterxml.jackson.databind.JsonNode
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
 import org.apache.commons.io.IOUtils
+import org.apache.http.HttpEntity
+import org.apache.http.HttpResponse
+import org.apache.http.HttpStatus
 import org.apache.http.client.ClientProtocolException
 import org.apache.http.client.config.RequestConfig
 import org.apache.http.client.methods.HttpDelete
@@ -164,11 +167,25 @@ abstract class BaseBlueprintWebClientService<out E : RestClientProperties> : Blu
         BlueprintWebClientService.WebClientResponse<T> {
             val httpResponse = httpClient().execute(httpUriRequest)
             val statusCode = httpResponse.statusLine.statusCode
-            httpResponse.entity.content.use {
-                val body = getResponse(it, responseType)
+            val entity: HttpEntity? = httpResponse.entity
+            if (canResponseHaveBody(httpResponse)) {
+                entity!!.content.use {
+                    val body = getResponse(it, responseType)
+                    return BlueprintWebClientService.WebClientResponse(statusCode, body)
+                }
+            } else {
+                val constructor = responseType.getConstructor()
+                val body = constructor.newInstance()
                 return BlueprintWebClientService.WebClientResponse(statusCode, body)
             }
         }
+    fun canResponseHaveBody(response: HttpResponse): Boolean {
+        val status = response.statusLine.statusCode
+        return response.entity !== null &&
+            status != HttpStatus.SC_NO_CONTENT &&
+            status != HttpStatus.SC_NOT_MODIFIED &&
+            status != HttpStatus.SC_RESET_CONTENT
+    }
 
     open suspend fun getNB(path: String): BlueprintWebClientService.WebClientResponse<String> {
         return getNB(path, null, String::class.java)
index 0309966..e865a00 100644 (file)
@@ -39,6 +39,8 @@ 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.HttpMethod
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
 import org.springframework.http.server.reactive.HttpHandler
 import org.springframework.security.config.web.server.ServerHttpSecurity
 import org.springframework.security.core.userdetails.MapReactiveUserDetailsService
@@ -184,7 +186,7 @@ class RestClientServiceTest {
         assertEquals(res, "Basic request arrived successfully")
     }
 
-    // @Test
+    @Test
     fun testSampleAaiReq() {
         val restClientService = bluePrintRestLibPropertyService
             .blueprintWebClientService("test")
@@ -282,6 +284,51 @@ class RestClientServiceTest {
         assertEquals(res5, "The patch request is success")
         assertEquals(res6, "The message is successfully deleted")
     }
+    @Test
+    fun testDeleteWith204StatusAndResponseAsString() {
+        val restClientService = bluePrintRestLibPropertyService
+            .blueprintWebClientService("sample")
+        val headers = mutableMapOf<String, String>()
+        headers["X-Transaction-Id"] = "1234"
+        val response = restClientService.exchangeResource(
+            HttpMethod.DELETE.name,
+            "/sample/name", ""
+        )
+        assertEquals(response.status, 204)
+        assertEquals(response.body, "")
+    }
+
+    @Test
+    fun testDeleteWith204StatusAndResponseAsCustomerWithDefaultConstructor() {
+        val restClientService = bluePrintRestLibPropertyService
+            .blueprintWebClientService("sample")
+        val headers = mutableMapOf<String, String>()
+        headers["X-Transaction-Id"] = "1234"
+        runBlocking {
+            val response = restClientService.exchangeNB(
+                HttpMethod.DELETE.name,
+                "/sample/customersWithDefaultConstructor", "", headers, CustomerWithDefaultConstructor::class.java
+            )
+            assertEquals(response.status, 204)
+            assertEquals(response.body, CustomerWithDefaultConstructor())
+        }
+    }
+
+    // @Test
+    fun testDeleteWith204StatusAndResponseAsCustomerWithoutDefaultConstructor() {
+        val restClientService = bluePrintRestLibPropertyService
+            .blueprintWebClientService("sample")
+        val headers = mutableMapOf<String, String>()
+        headers["X-Transaction-Id"] = "1234"
+        runBlocking {
+            val response = restClientService.exchangeNB(
+                HttpMethod.DELETE.name,
+                "/sample/customersWithoutDefaultConstructor", "", headers, CustomerWithoutDefaultConstructor::class.java
+            )
+            assertEquals(response.status, 204)
+            assertEquals(response.body, CustomerWithoutDefaultConstructor(""))
+        }
+    }
 }
 
 /**
@@ -293,6 +340,10 @@ open class SampleController {
 
     @GetMapping("/name")
     fun getName(): String = "Sample Controller"
+    @DeleteMapping("/name")
+    fun deleteNameWith204StatusAndEmptyBody(): ResponseEntity<Unit> {
+        return ResponseEntity(HttpStatus.NO_CONTENT)
+    }
 
     @GetMapping("/query")
     fun getQuery(@RequestParam("id") id: String): String =
@@ -377,6 +428,17 @@ open class SampleController {
         }
         return "The message is successfully deleted"
     }
+    @DeleteMapping("/customersWithDefaultConstructor")
+    fun deleteCustomersWith204StatusAndResponseAsCustomerWithDefaultConstructor():
+        ResponseEntity<CustomerWithDefaultConstructor> {
+            return ResponseEntity(CustomerWithDefaultConstructor(), HttpStatus.NO_CONTENT)
+        }
+
+    @DeleteMapping("/customersWithoutDefaultConstructor")
+    fun deleteCustomersWith204StatusAndResponseAsCustomerWithoutDefaultConstructor():
+        ResponseEntity<CustomerWithoutDefaultConstructor> {
+            return ResponseEntity(CustomerWithoutDefaultConstructor(""), HttpStatus.NO_CONTENT)
+        }
 }
 
 /**
@@ -414,3 +476,13 @@ data class Customer(
     val type: String,
     val resource: String
 )
+
+data class CustomerWithoutDefaultConstructor(
+    val name: String
+)
+
+data class CustomerWithDefaultConstructor(
+    val name: String
+) {
+    constructor() : this("")
+}