Fix exception handling in AbstractComponentFunction 24/109424/1
authorJozsef Csongvai <jozsef.csongvai@bell.ca>
Mon, 22 Jun 2020 18:05:45 +0000 (14:05 -0400)
committerJozsef Csongvai <jozsef.csongvai@bell.ca>
Mon, 22 Jun 2020 18:18:57 +0000 (14:18 -0400)
Moved try-catch to applyNB so that it also catches exceptions
in prepareRequestNB. This restores exception handling to the
way it was before introduction of locking feature.

Issue-ID: CCSDK-2460
Signed-off-by: Jozsef Csongvai <jozsef.csongvai@bell.ca>
Change-Id: I20326d9a79ac5fbae630eda8530e8428cdb4f84c

ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt
ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/scripts/AbstractComponentFunctionTest.kt

index 211bf76..4cd8097 100644 (file)
@@ -105,7 +105,7 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic
         /** Resolve and validate lock properties */
         implementation.lock?.apply {
             val resolvedValues = bluePrintRuntimeService.resolvePropertyAssignments(
-                    nodeTemplateName,
+                    BluePrintConstants.MODEL_DEFINITION_TYPE_NODE_TEMPLATE,
                     interfaceName,
                     mutableMapOf("key" to this.key, "acquireTimeout" to this.acquireTimeout))
             this.key = resolvedValues["key"] ?: "".asJsonType()
@@ -153,21 +153,14 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic
     }
 
     override suspend fun applyNB(executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput {
-        prepareRequestNB(executionServiceInput)
-        return implementation.lock?.let {
-            bluePrintClusterService.clusterLock("${it.key.textValue()}@$CDS_LOCK_GROUP")
-                    .executeWithLock(it.acquireTimeout.intValue().times(1000).toLong()) {
-                        applyNBWithTimeout(executionServiceInput)
-                    }
-        } ?: applyNBWithTimeout(executionServiceInput)
-    }
-
-    private suspend fun applyNBWithTimeout(executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput {
         try {
-            withTimeout((implementation.timeout * 1000).toLong()) {
-                log.debug("DEBUG::: AbstractComponentFunction.withTimeout section ${implementation.timeout} seconds")
-                processNB(executionServiceInput)
-            }
+            prepareRequestNB(executionServiceInput)
+            implementation.lock?.let {
+                bluePrintClusterService.clusterLock("${it.key.textValue()}@$CDS_LOCK_GROUP")
+                        .executeWithLock(it.acquireTimeout.intValue().times(1000).toLong()) {
+                            applyNBWithTimeout(executionServiceInput)
+                        }
+            } ?: applyNBWithTimeout(executionServiceInput)
         } catch (runtimeException: RuntimeException) {
             log.error("failed in ${getName()} : ${runtimeException.message}", runtimeException)
             recoverNB(runtimeException, executionServiceInput)
@@ -175,6 +168,13 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic
         return prepareResponseNB()
     }
 
+    private suspend fun applyNBWithTimeout(executionServiceInput: ExecutionServiceInput) =
+            withTimeout((implementation.timeout * 1000).toLong()) {
+                log.debug("DEBUG::: AbstractComponentFunction.withTimeout " +
+                        "section ${implementation.timeout} seconds")
+                processNB(executionServiceInput)
+            }
+
     fun getOperationInput(key: String): JsonNode {
         return operationInputs[key]
             ?: throw BluePrintProcessorException("couldn't get the operation input($key) value.")
index e0b6905..0f9dfd1 100644 (file)
@@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.databind.node.ObjectNode
 import io.mockk.every
 import io.mockk.mockk
+import io.mockk.spyk
 import io.mockk.verify
 import kotlinx.coroutines.runBlocking
 import org.junit.Test
@@ -53,6 +54,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.test.context.ContextConfiguration
 import org.springframework.test.context.junit4.SpringRunner
+import java.lang.RuntimeException
 import kotlin.test.BeforeTest
 import kotlin.test.assertEquals
 import kotlin.test.assertNotNull
@@ -203,6 +205,27 @@ class AbstractComponentFunctionTest {
         }
     }
 
+    @Test
+    fun `applyNB should catch exceptions and call recoverNB`() {
+        val exception = RuntimeException("Intentional test exception")
+        every {
+            bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
+        } throws exception
+        every {
+            blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
+        } returns Implementation().apply {
+            this.lock = LockAssignment().apply { this.key = "testing-lock".asJsonType() }
+        }
+
+        val component: AbstractComponentFunction = spyk(SampleComponent())
+        component.bluePrintRuntimeService = bluePrintRuntimeService
+        component.bluePrintClusterService = blueprintClusterService
+        val input = getMockedInput(bluePrintRuntimeService)
+
+        runBlocking { component.applyNB(input) }
+        verify { runBlocking { component.recoverNB(exception, input) } }
+    }
+
     @Test
     fun `applyNB - when lock is present use ClusterLock`() {