Enhancing BluePrintJinjaTemplateService 80/133880/1
authorSingal, Kapil (ks220y) <ks220y@att.com>
Mon, 8 May 2023 13:10:58 +0000 (09:10 -0400)
committerKAPIL SINGAL <ks220y@att.com>
Mon, 8 May 2023 13:46:41 +0000 (13:46 +0000)
* Using CustomJinjavaInterpreter to override getAsString API, and returning context.currentNode.master.image instead of empty string
* Earlier rendered result was not keeping unresolved variable rather replacing with empty string, and above helps keeping those.
* Upgrading jinja.version to 2.7.0 from 2.5.1 and adding related Junit Test

Issue-ID: CCSDK-3895
Signed-off-by: Singal, Kapil (ks220y) <ks220y@att.com>
Change-Id: I00da64811883957f44f819a44405e073ed7a7755

components/model-catalog/blueprint-model/archetype-blueprint/src/main/resources/archetype-resources/Tests/kotlin/default-variable-value-data.txt
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintJinjaTemplateService.kt
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintTemplateServiceTest.kt
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template-resolved.jinja [new file with mode: 0644]
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template.jinja [new file with mode: 0644]
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-value-data.json
ms/blueprintsprocessor/parent/pom.xml

index fdc348b..d3a7f0f 100644 (file)
@@ -21,9 +21,12 @@ import com.fasterxml.jackson.databind.JsonNode
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.hubspot.jinjava.Jinjava
 import com.hubspot.jinjava.JinjavaConfig
+import com.hubspot.jinjava.interpret.Context
+import com.hubspot.jinjava.interpret.InterpreterFactory
 import com.hubspot.jinjava.interpret.JinjavaInterpreter
 import com.hubspot.jinjava.loader.ResourceLocator
 import com.hubspot.jinjava.loader.ResourceNotFoundException
+import com.hubspot.jinjava.objects.serialization.PyishObjectMapper
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintJsonNodeFactory
@@ -33,6 +36,7 @@ import java.io.IOException
 import java.nio.charset.Charset
 import java.nio.file.Files.readAllBytes
 import java.nio.file.Paths
+import java.util.Objects
 
 object BluePrintJinjaTemplateService {
 
@@ -89,27 +93,46 @@ object BluePrintJinjaTemplateService {
         additionalContext: MutableMap<String, Any>,
         resourceLocator: ResourceLocator? = null
     ): String {
-        val jinJava = Jinjava(JinjavaConfig())
-        if (resourceLocator != null) {
-            jinJava.resourceLocator = resourceLocator
-        }
-
-        val mapper = ObjectMapper()
-        val nodeFactory = BluePrintJsonNodeFactory()
-        mapper.nodeFactory = nodeFactory
-
         // Add the JSON Data to the context
         if (json.isNotEmpty()) {
-            val jsonNode = mapper.readValue<JsonNode>(json, JsonNode::class.java)
+            val mapper = ObjectMapper().setNodeFactory(BluePrintJsonNodeFactory())
+            val jsonNode = mapper.readValue(json, JsonNode::class.java)
                 ?: throw BluePrintProcessorException("couldn't get json node from json")
             if (ignoreJsonNull) {
                 jsonNode.removeNullNode()
             }
+            additionalContext.putAll(mapper.readValue(json, object : TypeReference<Map<String, Any>>() {}))
+        }
+
+        val jinjava = Jinjava(
+            JinjavaConfig(object : InterpreterFactory {
+                override fun newInstance(interpreter: JinjavaInterpreter): JinjavaInterpreter {
+                    return CustomJinjavaInterpreter(interpreter)
+                }
 
-            val jsonMap: Map<String, Any> = mapper.readValue(json, object : TypeReference<Map<String, Any>>() {})
-            additionalContext.putAll(jsonMap)
+                override fun newInstance(jinjava: Jinjava, context: Context, config: JinjavaConfig): JinjavaInterpreter {
+                    return CustomJinjavaInterpreter(jinjava, context, config)
+                }
+            })
+        )
+
+        if (resourceLocator != null) {
+            jinjava.resourceLocator = resourceLocator
         }
 
-        return jinJava.render(template, additionalContext)
+        return jinjava.render(template, additionalContext)
+    }
+
+    class CustomJinjavaInterpreter : JinjavaInterpreter {
+        constructor(interpreter: JinjavaInterpreter) : super(interpreter)
+        constructor(jinjava: Jinjava, context: Context, config: JinjavaConfig) : super(jinjava, context, config)
+
+        // Overriding actual getAsString method to return `context.currentNode.master.image` instead of empty string
+        override fun getAsString(`object`: Any?): String {
+            return if (config.legacyOverrides.isUsePyishObjectMapper)
+                PyishObjectMapper.getAsUnquotedPyishString(`object`)
+            else
+                Objects.toString(`object`, context.currentNode.master.image)
+        }
     }
 }
index 0e93ccf..87591e1 100644 (file)
@@ -61,22 +61,36 @@ class BluePrintTemplateServiceTest {
             )
 
             val content = BluePrintJinjaTemplateService.generateContent(template, json, false, element)
-            assertNotNull(content, "failed to generate content for velocity template")
+            assertNotNull(content, "failed to generate content for jinja template")
         }
     }
 
     @Test
-    fun `no value variable should evaluate to default value - standalone template mesh test`() {
+    fun `Unresolved variable should be kept as-is - standalone velocity template mesh test`() {
         runBlocking {
             val template =
                 JacksonUtils.getClassPathFileContent("templates/default-variable-value-velocity-template.vtl")
             val json = JacksonUtils.getClassPathFileContent("templates/default-variable-value-data.json")
 
             val content = BluePrintVelocityTemplateService.generateContent(template, json)
-            // first line represents a variable whose value was successfully retrieved, second line contains a variable
-            // whose value could not be evaluated
-            val expected = "sample-hostname\n\${node0_backup_router_address}"
+            // first line represents a variable whose value was successfully retrieved,
+            // second line contains a variable whose value could not be evaluated
+            val expected = "sample-node0_hostname\n\${node0_backup_router_address}"
             assertEquals(expected, content, "No value variable should use default value")
         }
     }
+
+    @Test
+    fun `Unresolved variable should be kept as-is - standalone jinja template mesh test`() {
+        runBlocking {
+            val context = JacksonUtils.getClassPathFileContent("templates/default-variable-value-data.json")
+            val jinjaTemplate =
+                JacksonUtils.getClassPathFileContent("templates/default-variable-jinja-template.jinja")
+            val renderedContent =
+                BluePrintJinjaTemplateService.generateContent(jinjaTemplate, context, false, mutableMapOf())
+            val expectedContent =
+                JacksonUtils.getClassPathFileContent("templates/default-variable-jinja-template-resolved.jinja")
+            assertEquals(expectedContent, renderedContent, "No value variable should use default value")
+        }
+    }
 }
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template-resolved.jinja b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template-resolved.jinja
new file mode 100644 (file)
index 0000000..b9617d6
--- /dev/null
@@ -0,0 +1,6 @@
+sample-node0_hostname
+{{ node1_hostname }}
+This will be kept as-is {{ node0_backup_router_address }}
+sample-node0_hostname
+Even this one {{ node1_backup_router_address }} as it doesn't matter if variable is surrounded by text
+sample-node2_backup_router_address {{ node1_backup_router_address }} Even this One if multiple variable in same line
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template.jinja b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template.jinja
new file mode 100644 (file)
index 0000000..5d483e3
--- /dev/null
@@ -0,0 +1,6 @@
+{{ node0_hostname }}
+{{ node1_hostname }}
+This will be kept as-is {{ node0_backup_router_address }}
+{{ node0_hostname }}
+Even this one {{ node1_backup_router_address }} as it doesn't matter if variable is surrounded by text
+{{ node2_backup_router_address }} {{ node1_backup_router_address }} Even this One if multiple variable in same line
index 3de8e9b..7db6003 100755 (executable)
         <json.unit.version>2.8.0</json.unit.version>
         <xmlunit.version>2.6.3</xmlunit.version>
 
-  
-   
         <sshd.version>2.2.0</sshd.version>
         <jsch.version>0.1.55</jsch.version>
         <jslt.version>0.1.8</jslt.version>
         <jython.version>2.7.2</jython.version>
-        <jinja.version>2.5.1</jinja.version>
+        <jinja.version>2.7.0</jinja.version>
         <guava.version>27.0.1-jre</guava.version>
         <json-patch.version>1.9</json-patch.version>
         <json-smart.version>2.4.6</json-smart.version>