Repository: authorjapps/zerocode
Pull request #223 (2019-03-22 17:28:19)

ISS-220 - Producer, Consumer - Uniqueness


Patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java
index 28c60d4e..e7acad54 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java
@@ -29,9 +29,9 @@ import org.slf4j.Logger;
 import java.util.List;
 import java.util.Map;
 
-import static org.jsmart.zerocode.core.engine.preprocessor.ZeroCodeJsonTestProcesorImpl.JSON_PAYLOAD_FILE;
-import static org.jsmart.zerocode.core.utils.SmartUtils.getAllTokens;
+import static org.jsmart.zerocode.core.engine.preprocessor.ZeroCodeTokens.JSON_PAYLOAD_FILE;
 import static org.jsmart.zerocode.core.utils.SmartUtils.readJsonAsString;
+import static org.jsmart.zerocode.core.utils.TokenUtils.getTestCaseTokens;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -160,7 +160,7 @@ public class ZeroCodeExternalFileProcessorImpl implements ZeroCodeExternalFilePr
 
     private String getJsonFilePhToken(String valueString) {
         if (valueString != null) {
-            List<String> allTokens = getAllTokens(valueString);
+            List<String> allTokens = getTestCaseTokens(valueString);
             if (allTokens != null && !allTokens.isEmpty()) {
                 return allTokens.get(0);
             }
@@ -170,7 +170,7 @@ public class ZeroCodeExternalFileProcessorImpl implements ZeroCodeExternalFilePr
 
     boolean checkDigNeeded(Step thisStep) throws JsonProcessingException {
         String stepJson = objectMapper.writeValueAsString(thisStep);
-        List<String> allTokens = getAllTokens(stepJson);
+        List<String> allTokens = getTestCaseTokens(stepJson);
 
         return allTokens.toString().contains(JSON_PAYLOAD_FILE);
     }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeTokens.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeTokens.java
new file mode 100644
index 00000000..22402909
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeTokens.java
@@ -0,0 +1,37 @@
+package org.jsmart.zerocode.core.engine.preprocessor;
+
+import java.util.List;
+
+import static java.util.Arrays.asList;
+
+public class ZeroCodeTokens {
+    /*
+     * General place holders
+     */
+    public static final String JSON_PAYLOAD_FILE = "JSON.FILE:";
+
+    public static final String PREFIX_ASU = "ASU";
+    public static final String XML_FILE = "XML.FILE:";
+    public static final String RANDOM_UU_ID = "RANDOM.UUID";
+    public static final String RECORD_DUMP = "RECORD.DUMP:";
+    public static final String RANDOM_NUMBER = "RANDOM.NUMBER";
+    public static final String RANDOM_STRING_PREFIX = "RANDOM.STRING:";
+    public static final String STATIC_ALPHABET = "STATIC.ALPHABET:";
+    public static final String LOCALDATE_TODAY = "LOCAL.DATE.TODAY:";
+    public static final String LOCALDATETIME_NOW = "LOCAL.DATETIME.NOW:";
+
+
+    public static List<String> getKnownTokens() {
+        return asList(
+                PREFIX_ASU,
+                RANDOM_NUMBER,
+                RANDOM_STRING_PREFIX,
+                STATIC_ALPHABET,
+                LOCALDATE_TODAY,
+                LOCALDATETIME_NOW,
+                XML_FILE,
+                RANDOM_UU_ID,
+                RECORD_DUMP
+        );
+    }
+}
diff --git a/core/src/main/java/org/jsmart/zerocode/core/kafka/common/KafkaCommonUtils.java b/core/src/main/java/org/jsmart/zerocode/core/kafka/common/KafkaCommonUtils.java
new file mode 100644
index 00000000..ba6f903b
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/kafka/common/KafkaCommonUtils.java
@@ -0,0 +1,18 @@
+package org.jsmart.zerocode.core.kafka.common;
+
+import java.util.Properties;
+
+import static org.jsmart.zerocode.core.utils.TokenUtils.resolveKnownTokens;
+
+public class KafkaCommonUtils {
+
+    public static void resolveValuePlaceHolders(Properties properties) {
+        properties.keySet().forEach(key -> {
+            String value = properties.getProperty(key.toString());
+            String resolvedValue = resolveKnownTokens(value);
+            if(!value.equals(resolvedValue)){
+                properties.put(key, resolvedValue);
+            }
+        });
+    }
+}
diff --git a/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaConsumerHelper.java b/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaConsumerHelper.java
index 0eb89a44..af6bc1d6 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaConsumerHelper.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaConsumerHelper.java
@@ -29,6 +29,7 @@ import static java.lang.Long.parseLong;
 import static java.util.Optional.ofNullable;
 import static org.apache.commons.lang3.StringUtils.isEmpty;
 import static org.jsmart.zerocode.core.kafka.KafkaConstants.*;
+import static org.jsmart.zerocode.core.kafka.common.KafkaCommonUtils.resolveValuePlaceHolders;
 import static org.jsmart.zerocode.core.utils.SmartUtils.prettyPrintJson;
 
 public class KafkaConsumerHelper {
@@ -42,6 +43,8 @@ public class KafkaConsumerHelper {
             properties.load(propsIs);
             properties.put("bootstrap.servers", bootStrapServers);
 
+            resolveValuePlaceHolders(properties);
+
             final Consumer consumer = new KafkaConsumer(properties);
             consumer.subscribe(Collections.singletonList(topic));
 
diff --git a/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaProducerHelper.java b/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaProducerHelper.java
index 90944283..bf12fa2c 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaProducerHelper.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/kafka/helper/KafkaProducerHelper.java
@@ -21,24 +21,27 @@ import java.util.Properties;
 
 import static org.jsmart.zerocode.core.kafka.KafkaConstants.RAW;
 import static org.jsmart.zerocode.core.kafka.common.CommonConfigs.BOOTSTRAP_SERVERS;
+import static org.jsmart.zerocode.core.kafka.common.KafkaCommonUtils.resolveValuePlaceHolders;
 import static org.jsmart.zerocode.core.kafka.error.KafkaMessageConstants.NO_RECORD_FOUND_TO_SEND;
+import static org.jsmart.zerocode.core.utils.TokenUtils.resolveKnownTokens;
 
 public class KafkaProducerHelper {
     private static final Logger LOGGER = LoggerFactory.getLogger(KafkaProducerHelper.class);
     private static final Gson gson = new GsonSerDeProvider().get();
     private static final ObjectMapper objectMapper = new ObjectMapperProvider().get();
 
-    public static Producer<Long, String> createProducer(String bootStrapServers, String producerPropertyFile) {
-
+    public  static Producer<Long, String> createProducer(String bootStrapServers, String producerPropertyFile) {
         try (InputStream propsIs = Resources.getResource(producerPropertyFile).openStream()) {
             Properties properties = new Properties();
             properties.load(propsIs);
             properties.put(BOOTSTRAP_SERVERS, bootStrapServers);
 
+            resolveValuePlaceHolders(properties);
+
             return new KafkaProducer(properties);
 
         } catch (IOException e) {
-            throw new RuntimeException("Exception while reading kafka producer properties" + e);
+            throw new RuntimeException("Exception while reading kafka producer properties - " + e);
         }
     }
 
diff --git a/core/src/main/java/org/jsmart/zerocode/core/runner/ScenarioSingleStepStatusNotifier.java b/core/src/main/java/org/jsmart/zerocode/core/runner/ScenarioSingleStepStatusNotifier.java
deleted file mode 100644
index 0b7b3ca0..00000000
--- a/core/src/main/java/org/jsmart/zerocode/core/runner/ScenarioSingleStepStatusNotifier.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.jsmart.zerocode.core.runner;
-
-import org.jsmart.zerocode.core.engine.assertion.AssertionReport;
-
-import java.util.List;
-
-public interface ScenarioSingleStepStatusNotifier {
-    Boolean notifyFlowStepAssertionFailed(String scenarioName,
-                                          String stepName,
-                                          List<AssertionReport> failureReportList);
-    Boolean notifyFlowStepExecutionException(String scenarioName, String stepName, Exception ex);
-    Boolean notifyFlowStepExecutionPassed(String scenarioName, String stepName);
-}
diff --git a/core/src/main/java/org/jsmart/zerocode/core/utils/RunnerUtils.java b/core/src/main/java/org/jsmart/zerocode/core/utils/RunnerUtils.java
index 518ae247..f64656dd 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/utils/RunnerUtils.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/utils/RunnerUtils.java
@@ -9,8 +9,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import static org.jsmart.zerocode.core.utils.SmartUtils.getAllTokens;
 import static org.jsmart.zerocode.core.utils.SmartUtils.getEnvPropertyValue;
+import static org.jsmart.zerocode.core.utils.TokenUtils.getTestCaseTokens;
 
 /**
  * This code is used by Unit and Package runner.
@@ -30,7 +30,7 @@ public class RunnerUtils {
 
         String envPropNameWithPrefix = envProperty.value();
 
-        List<String> allTokens = getAllTokens(envPropNameWithPrefix);
+        List<String> allTokens = getTestCaseTokens(envPropNameWithPrefix);
 
         if(allTokens.size() >= 1 && null != getEnvPropertyValue(allTokens.get(0))){
 
diff --git a/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java b/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java
index 6e6ff235..b733ee85 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java
@@ -17,15 +17,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static java.nio.charset.Charset.defaultCharset;
@@ -152,27 +144,6 @@ public class SmartUtils {
         return mapper;
     }
 
-    /**
-     * This method was introduced later,
-     * But Framework uses- ZeroCodeJsonTestProcesorImpl#getAllTokens(java.lang.String)
-     *
-     * @param aString - Containing the pattern
-     * @return List of strings matching the pattern
-     */
-    public static List<String> getAllTokens(String aString) {
-
-        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
-        Matcher matcher = pattern.matcher(aString);
-
-        List<String> keyTokens = new ArrayList<>();
-
-        while (matcher.find()) {
-            keyTokens.add(matcher.group(1));
-        }
-
-        return keyTokens;
-    }
-
     public static String resolveToken(String stringWithToken, Map<String, String> paramMap) {
         StrSubstitutor sub = new StrSubstitutor(paramMap);
         return sub.replace(stringWithToken);
diff --git a/core/src/main/java/org/jsmart/zerocode/core/utils/TokenUtils.java b/core/src/main/java/org/jsmart/zerocode/core/utils/TokenUtils.java
new file mode 100644
index 00000000..c82fc1aa
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/utils/TokenUtils.java
@@ -0,0 +1,125 @@
+package org.jsmart.zerocode.core.utils;
+
+import org.apache.commons.lang.text.StrSubstitutor;
+
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static java.util.UUID.randomUUID;
+import static org.apache.commons.lang.StringEscapeUtils.escapeJava;
+import static org.jsmart.zerocode.core.engine.preprocessor.ZeroCodeTokens.*;
+
+public class TokenUtils {
+
+    public static String resolveKnownTokens(String requestJsonOrAnyString) {
+        Map<String, Object> paramMap = new HashMap<>();
+
+        final List<String> testCaseTokens = getTestCaseTokens(requestJsonOrAnyString);
+
+        testCaseTokens.forEach(runTimeToken -> {
+            populateParamMap(paramMap, runTimeToken);
+        });
+
+        StrSubstitutor sub = new StrSubstitutor(paramMap);
+
+        return sub.replace(requestJsonOrAnyString);
+    }
+
+    public static void populateParamMap(Map<String, Object> paramaMap, String runTimeToken) {
+        getKnownTokens().forEach(inStoreToken -> {
+                    if (runTimeToken.startsWith(inStoreToken)) {
+                        if (runTimeToken.startsWith(RANDOM_NUMBER)) {
+                            paramaMap.put(runTimeToken, System.currentTimeMillis() + "");
+
+                        } else if (runTimeToken.startsWith(RANDOM_STRING_PREFIX)) {
+                            int length = Integer.parseInt(runTimeToken.substring(RANDOM_STRING_PREFIX.length()));
+                            paramaMap.put(runTimeToken, createRandomAlphaString(length));
+
+                        } else if (runTimeToken.startsWith(STATIC_ALPHABET)) {
+                            int length = Integer.parseInt(runTimeToken.substring(STATIC_ALPHABET.length()));
+                            paramaMap.put(runTimeToken, createStaticAlphaString(length));
+
+                        } else if (runTimeToken.startsWith(LOCALDATE_TODAY)) {
+                            String formatPattern = runTimeToken.substring(LOCALDATE_TODAY.length());
+                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern);
+                            paramaMap.put(runTimeToken, LocalDate.now().format(formatter));
+
+                        } else if (runTimeToken.startsWith(LOCALDATETIME_NOW)) {
+                            String formatPattern = runTimeToken.substring(LOCALDATETIME_NOW.length());
+                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern);
+                            paramaMap.put(runTimeToken, LocalDateTime.now().format(formatter));
+
+                        } else if (runTimeToken.startsWith(XML_FILE)) {
+                            String xmlFileResource = runTimeToken.substring(XML_FILE.length());
+                            final String xmlString = getXmlContent(xmlFileResource);
+                            // Used escapeJava, do not use escapeXml as it replaces
+                            // with GT LT etc ie what exactly you don't want
+                            paramaMap.put(runTimeToken, escapeJava(xmlString));
+
+                        } else if (runTimeToken.startsWith(RANDOM_UU_ID)) {
+                            paramaMap.put(runTimeToken, randomUUID().toString());
+                        }
+                    }
+                }
+        );
+
+    }
+
+    /**
+     * This method was introduced later,
+     * But Framework uses- ZeroCodeJsonTestProcesorImpl#getTestCaseTokens(java.lang.String)
+     */
+    public static List<String> getTestCaseTokens(String aString) {
+
+        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
+        Matcher matcher = pattern.matcher(aString);
+
+        List<String> keyTokens = new ArrayList<>();
+
+        while (matcher.find()) {
+            keyTokens.add(matcher.group(1));
+        }
+
+        return keyTokens;
+    }
+
+    public static String createRandomAlphaString(int length) {
+        StringBuilder builder = new StringBuilder();
+        Random r = new Random();
+        for (int i = 0; i < length; i++) {
+            builder.append((char) ('a' + r.nextInt(26)));
+        }
+        String randomString = builder.toString();
+        return randomString;
+    }
+
+    public static String createStaticAlphaString(int length) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < length; i++) {
+            builder.append((char) ('a' + i));
+
+            /*
+             * This will repeat after A to Z
+             */
+            i = i >= 26 ? 0 : i;
+        }
+
+        return builder.toString();
+    }
+
+
+    public static String getXmlContent(String xmlFileResource) {
+        try {
+            return SmartUtils.readJsonAsString(xmlFileResource);
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new RuntimeException("Oops! Problem occurred while reading the XML file '" + xmlFileResource
+                    + "', details:" + e);
+        }
+    }
+}


Test patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java
index 5e046766..ea36d8ef 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java
@@ -25,7 +25,7 @@ public interface ZeroCodeJsonTestProcesor {
 
     String resolveStringJson(String requestJsonAsString, String resolvedScenarioState);
 
-    List<String> getAllTokens(String requestJsonAsString);
+    String resolveKnownTokensAndProperties(String requestJsonOrAnyString);
 
     String resolveJsonPaths(String resolvedFromTemplate, String jsonString);
 
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
index 8104412a..21a9b0b7 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
@@ -24,20 +24,14 @@ import com.google.inject.name.Named;
 import com.jayway.jsonpath.JsonPath;
 import org.apache.commons.lang.text.StrSubstitutor;
 import org.jsmart.zerocode.core.engine.assertion.*;
-import org.jsmart.zerocode.core.utils.SmartUtils;
 
 import java.io.IOException;
 import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import static java.lang.String.format;
-import static java.util.UUID.randomUUID;
 import static org.apache.commons.lang.StringEscapeUtils.escapeJava;
+import static org.jsmart.zerocode.core.utils.TokenUtils.*;
 import static org.slf4j.LoggerFactory.getLogger;
 
 public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
@@ -47,36 +41,9 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
     final List<String> propertyKeys = new ArrayList<>();
     final Properties properties = new Properties();
 
-    /*
-     * General place holders
-     */
-    public static final String JSON_PAYLOAD_FILE = "JSON.FILE:";
-
-    private static final String PREFIX_ASU = "ASU";
-    private static final String RANDOM_NUMBER = "RANDOM.NUMBER";
-    private static final String RANDOM_STRING_PREFIX = "RANDOM.STRING:";
-    private static final String STATIC_ALPHABET = "STATIC.ALPHABET:";
-    private static final String LOCALDATE_TODAY = "LOCAL.DATE.TODAY:";
-    private static final String LOCALDATETIME_NOW = "LOCAL.DATETIME.NOW:";
-    private static final String XML_FILE = "XML.FILE:";
-    private static final String RANDOM_UU_ID = "RANDOM.UUID";
-    private static final String RECORD_DUMP = "RECORD.DUMP:";
-
-    private static final List<String> availableTokens = Arrays.asList(
-            PREFIX_ASU,
-            RANDOM_NUMBER,
-            RANDOM_STRING_PREFIX,
-            STATIC_ALPHABET,
-            LOCALDATE_TODAY,
-            LOCALDATETIME_NOW,
-            XML_FILE,
-            RANDOM_UU_ID,
-            RECORD_DUMP
-    );
-
-    /*
-     * Assertion place holders
-     */
+    // -----------------------
+    // Assertion place holders
+    // -----------------------
     public static final String ASSERT_VALUE_NOT_NULL = "$NOT.NULL";
     public static final String ASSERT_VALUE_NULL = "$NULL";
     public static final String ASSERT_VALUE_EMPTY_ARRAY = "$[]";
@@ -89,7 +56,7 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
     public static final String ASSERT_VALUE_GREATER_THAN = "$GT.";
     public static final String ASSERT_VALUE_LESSER_THAN = "$LT.";
     public static final String ASSERT_PATH_VALUE_NODE = "$";
-    private static final String RAW_BODY = ".rawBody";
+    public static final String RAW_BODY = ".rawBody";
 
     private final ObjectMapper mapper;
     private final String hostFileName;
@@ -103,69 +70,28 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
 
     @Override
     public String resolveStringJson(String requestJsonOrAnyString, String scenarioStateJson) {
-        Map<String, Object> parammap = new HashMap<>();
-
-        final List<String> allTokens = getAllTokens(requestJsonOrAnyString);
-        allTokens.forEach(runTimeToken -> {
-            availableTokens.forEach(inStoreToken -> {
-                if (runTimeToken.startsWith(inStoreToken)) {
-                    if (runTimeToken.startsWith(RANDOM_NUMBER)) {
-                        parammap.put(runTimeToken, System.currentTimeMillis() + "");
-
-                    } else if (runTimeToken.startsWith(RANDOM_STRING_PREFIX)) {
-                        int length = Integer.parseInt(runTimeToken.substring(RANDOM_STRING_PREFIX.length()));
-                        parammap.put(runTimeToken, createRandomAlphaString(length));
-
-                    } else if (runTimeToken.startsWith(STATIC_ALPHABET)) {
-                        int length = Integer.parseInt(runTimeToken.substring(STATIC_ALPHABET.length()));
-                        parammap.put(runTimeToken, createStaticAlphaString(length));
-
-                    } else if (runTimeToken.startsWith(LOCALDATE_TODAY)) {
-                        String formatPattern = runTimeToken.substring(LOCALDATE_TODAY.length());
-                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern);
-                        parammap.put(runTimeToken, LocalDate.now().format(formatter));
-
-                    } else if (runTimeToken.startsWith(LOCALDATETIME_NOW)) {
-                        String formatPattern = runTimeToken.substring(LOCALDATETIME_NOW.length());
-                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern);
-                        parammap.put(runTimeToken, LocalDateTime.now().format(formatter));
-
-                    } else if (runTimeToken.startsWith(XML_FILE)) {
-                        String xmlFileResource = runTimeToken.substring(XML_FILE.length());
-                        final String xmlString = getXmlContent(xmlFileResource);
-                        // Used escapeJava, do not use escapeXml as it replaces
-                        // with GT LT etc ie what exactly you don't want
-                        parammap.put(runTimeToken, escapeJava(xmlString));
-
-                    } else if (runTimeToken.startsWith(RANDOM_UU_ID)) {
-                        parammap.put(runTimeToken, randomUUID().toString());
-                    }
-                }
-            });
+        String resolvedFromTemplate = resolveKnownTokensAndProperties(requestJsonOrAnyString);
+        return resolveJsonPaths(resolvedFromTemplate, scenarioStateJson);
+    }
 
-            if (isPropertyKey(runTimeToken)) {
-                parammap.put(runTimeToken, properties.get(runTimeToken));
-            }
+    @Override
+    public String resolveKnownTokensAndProperties(String requestJsonOrAnyString) {
+        Map<String, Object> paramMap = new HashMap<>();
 
-        });
+        final List<String> testCaseTokens = getTestCaseTokens(requestJsonOrAnyString);
 
-        StrSubstitutor sub = new StrSubstitutor(parammap);
-        String resolvedFromTemplate = sub.replace(requestJsonOrAnyString);
+        testCaseTokens.forEach(runTimeToken -> {
+            populateParamMap(paramMap, runTimeToken);
 
-        return resolveJsonPaths(resolvedFromTemplate, scenarioStateJson);
-    }
+            if (isPropertyKey(runTimeToken)) {
+                paramMap.put(runTimeToken, properties.get(runTimeToken));
+            }
 
-    @Override
-    public List<String> getAllTokens(String requestJsonAsString) {
-        List<String> keyTokens = new ArrayList<>();
+        });
 
-        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
-        Matcher matcher = pattern.matcher(requestJsonAsString);
-        while (matcher.find()) {
-            keyTokens.add(matcher.group(1));
-        }
+        StrSubstitutor sub = new StrSubstitutor(paramMap);
 
-        return keyTokens;
+        return sub.replace(requestJsonOrAnyString);
     }
 
     @Override
@@ -217,7 +143,7 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
     public List<String> getAllJsonPathTokens(String requestJsonAsString) {
         List<String> jsonPaths = new ArrayList<>();
 
-        final List<String> allTokens = getAllTokens(requestJsonAsString);
+        final List<String> allTokens = getTestCaseTokens(requestJsonAsString);
         allTokens.forEach(thisToken -> {
             if (thisToken.startsWith("$.")) {
                 jsonPaths.add(thisToken);
@@ -390,44 +316,6 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
         return failedReports;
     }
 
-    private String createRandomAlphaString(int length) {
-        StringBuilder builder = new StringBuilder();
-        Random r = new Random();
-        for (int i = 0; i < length; i++) {
-            builder.append((char) ('a' + r.nextInt(26)));
-        }
-        String randomString = builder.toString();
-        return randomString;
-    }
-
-    private String createStaticAlphaString(int length) {
-        StringBuilder builder = new StringBuilder();
-        for (int i = 0; i < length; i++) {
-            builder.append((char) ('a' + i));
-
-            /*
-             * This will repeat after A to Z
-             */
-            i = i >= 26 ? 0 : i;
-        }
-
-        return builder.toString();
-    }
-
-    public static List<String> getAvailableTokens() {
-        return availableTokens;
-    }
-
-    public String getXmlContent(String xmlFileResource) {
-        try {
-            return SmartUtils.readJsonAsString(xmlFileResource);
-        } catch (IOException e) {
-            e.printStackTrace();
-            throw new RuntimeException("Oops! Problem occurred while reading the XML file '" + xmlFileResource
-                    + "', details:" + e);
-        }
-    }
-
     private void loadAnnotatedHostProperties() {
         try {
             properties.load(getClass().getClassLoader().getResourceAsStream(hostFileName));
diff --git a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
index 2ac9c36d..008ba586 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
@@ -17,6 +17,8 @@ import java.util.HashMap;
 import java.util.List;
 
 import static org.hamcrest.CoreMatchers.*;
+import static org.jsmart.zerocode.core.utils.TokenUtils.getTestCaseTokens;
+import static org.jsmart.zerocode.core.utils.TokenUtils.resolveKnownTokens;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThat;
 
@@ -40,12 +42,12 @@ public class ZeroCodeJsonTestProcesorImplTest {
     public void willEvaluatePlaceHolder() throws Exception {
 
         String aString = "Hello_${WORLD}";
-        List<String> placeHolders = jsonPreProcessor.getAllTokens(aString);
+        List<String> placeHolders = getTestCaseTokens(aString);
         assertThat(placeHolders.size(), is(1));
         assertThat(placeHolders.get(0), is("WORLD"));
 
         aString = "Hello_${$.step_name}";
-        placeHolders = jsonPreProcessor.getAllTokens(aString);
+        placeHolders = getTestCaseTokens(aString);
         assertThat(placeHolders.size(), is(1));
         assertThat(placeHolders.get(0), is("$.step_name"));
 
@@ -69,7 +71,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         ScenarioSpec scenarioSpec = smartUtils.jsonFileToJava("09_test_engine/01_request_with_place_holders.json", ScenarioSpec.class);
         final String requestJsonAsString = scenarioSpec.getSteps().get(0).getRequest().toString();
 
-        final List<String> placeHolders = jsonPreProcessor.getAllTokens(requestJsonAsString);
+        final List<String> placeHolders = getTestCaseTokens(requestJsonAsString);
         assertThat(placeHolders.size(), is(4));
 
         final String resolvedRequestJson = jsonPreProcessor.resolveStringJson(requestJsonAsString, requestJsonAsString);
@@ -258,7 +260,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
 
         final String requestJsonAsString = scenarioSpec.getSteps().get(0).getRequest().toString();
 
-        final List<String> placeHolders = jsonPreProcessor.getAllTokens(requestJsonAsString);
+        final List<String> placeHolders = getTestCaseTokens(requestJsonAsString);
         assertThat(placeHolders.size(), is(2));
 
         final String resolvedRequestJson = jsonPreProcessor.resolveStringJson(requestJsonAsString, requestJsonAsString);
@@ -275,7 +277,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
 
         final String requestJsonAsString = scenarioSpec.getSteps().get(0).getRequest().toString();
 
-        final List<String> placeHolders = jsonPreProcessor.getAllTokens(requestJsonAsString);
+        final List<String> placeHolders = getTestCaseTokens(requestJsonAsString);
         assertThat(placeHolders.size(), is(2));
 
         final String resolvedRequestJson = jsonPreProcessor.resolveStringJson(requestJsonAsString, requestJsonAsString);
@@ -289,7 +291,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
                 "\t\"onlineOrderId\": \"${RANDOM.UUID}\"\n" +
                 "}";
 
-        final List<String> placeHolders = jsonPreProcessor.getAllTokens(requestJsonAsString);
+        final List<String> placeHolders = getTestCaseTokens(requestJsonAsString);
         assertThat(placeHolders.size(), is(1));
 
         final String resolvedRequestJson = jsonPreProcessor.resolveStringJson(requestJsonAsString, requestJsonAsString);
diff --git a/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java b/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java
index 712c984c..9c57ea73 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java
@@ -21,6 +21,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.IsNull.nullValue;
+import static org.jsmart.zerocode.core.utils.TokenUtils.getTestCaseTokens;
 
 @RunWith(JukitoRunner.class)
 //@UseModules(ApplicationMainModule.class) //<--- Only if you dont pass any value to it's constructor
@@ -99,12 +100,12 @@ public class SmartUtilsTest {
     public void willEvaluatePlaceHolder() throws Exception {
 
         String aString = "Hello_${WORLD}";
-        List<String> placeHolders = SmartUtils.getAllTokens(aString);
+        List<String> placeHolders = getTestCaseTokens(aString);
         Assert.assertThat(placeHolders.size(), is(1));
         Assert.assertThat(placeHolders.get(0), is("WORLD"));
 
         aString = "Hello_${$.step_name}";
-        placeHolders = SmartUtils.getAllTokens(aString);
+        placeHolders = getTestCaseTokens(aString);
         Assert.assertThat(placeHolders.size(), is(1));
         Assert.assertThat(placeHolders.get(0), is("$.step_name"));
 
@@ -114,11 +115,11 @@ public class SmartUtilsTest {
     public void testNullOrEmptyString_withPlaceHolders() throws Exception {
 
         String aString = "";
-        List<String> placeHolders = SmartUtils.getAllTokens(aString);
+        List<String> placeHolders = getTestCaseTokens(aString);
         Assert.assertThat(placeHolders.size(), is(0));
 
         aString = "Hello_";
-        placeHolders = SmartUtils.getAllTokens(aString);
+        placeHolders = getTestCaseTokens(aString);
         Assert.assertThat(placeHolders.size(), is(0));
     }
 
diff --git a/core/src/test/java/org/jsmart/zerocode/core/utils/TokenUtilsTest.java b/core/src/test/java/org/jsmart/zerocode/core/utils/TokenUtilsTest.java
new file mode 100644
index 00000000..f31ffeaa
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/core/utils/TokenUtilsTest.java
@@ -0,0 +1,20 @@
+package org.jsmart.zerocode.core.utils;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.jsmart.zerocode.core.utils.TokenUtils.resolveKnownTokens;
+import static org.junit.Assert.assertThat;
+
+public class TokenUtilsTest {
+
+    @Test
+    public void testResolve_knownTokens() {
+        String clientId = "zerocode-clientid_${RANDOM.NUMBER}";
+        String uniqueClientId = resolveKnownTokens(clientId);
+        String uniqueId = uniqueClientId.substring("zerocode-clientid_".length());
+
+        assertThat(Long.parseLong(uniqueId) > 1, is(true));
+
+    }
+}
\ No newline at end of file
diff --git a/kafka-testing/src/test/java/org/jsmart/zerocode/integration/tests/kafka/consume/KafkaConsumeUniqueGroupIdTest.java b/kafka-testing/src/test/java/org/jsmart/zerocode/integration/tests/kafka/consume/KafkaConsumeUniqueGroupIdTest.java
new file mode 100644
index 00000000..cec4a84e
--- /dev/null
+++ b/kafka-testing/src/test/java/org/jsmart/zerocode/integration/tests/kafka/consume/KafkaConsumeUniqueGroupIdTest.java
@@ -0,0 +1,18 @@
+package org.jsmart.zerocode.integration.tests.kafka.consume;
+
+import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@TargetEnv("kafka_servers/kafka_test_server_unique.properties")
+@RunWith(ZeroCodeUnitRunner.class)
+public class KafkaConsumeUniqueGroupIdTest {
+
+    @Test
+    @JsonTestCase("kafka/consume/test_kafka_consume.json")
+    public void testKafkaConsume() throws Exception {
+    }
+
+}
diff --git a/kafka-testing/src/test/java/org/jsmart/zerocode/integration/tests/kafka/produce/KafkaProduceUniqueClientIdTest.java b/kafka-testing/src/test/java/org/jsmart/zerocode/integration/tests/kafka/produce/KafkaProduceUniqueClientIdTest.java
new file mode 100644
index 00000000..a6b0c450
--- /dev/null
+++ b/kafka-testing/src/test/java/org/jsmart/zerocode/integration/tests/kafka/produce/KafkaProduceUniqueClientIdTest.java
@@ -0,0 +1,18 @@
+package org.jsmart.zerocode.integration.tests.kafka.produce;
+
+import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@TargetEnv("kafka_servers/kafka_test_server_unique.properties")
+@RunWith(ZeroCodeUnitRunner.class)
+public class KafkaProduceUniqueClientIdTest {
+
+    @Test
+    @JsonTestCase("kafka/produce/test_kafka_produce.json")
+    public void testProduce() throws Exception {
+    }
+
+}
diff --git a/kafka-testing/src/test/resources/kafka_servers/kafka_consumer.properties b/kafka-testing/src/test/resources/kafka_servers/kafka_consumer.properties
index 659d6464..3beae1cb 100755
--- a/kafka-testing/src/test/resources/kafka_servers/kafka_consumer.properties
+++ b/kafka-testing/src/test/resources/kafka_servers/kafka_consumer.properties
@@ -9,7 +9,6 @@ enable.auto.commit=false
 auto.offset.reset=earliest
 
 #
-#bootstrap.servers=localhost:9092
 #group.id=None
 #enable.auto.commit=true
 #key.deserializer=org.apache.kafka.common.serialization.LongDeserializer
diff --git a/kafka-testing/src/test/resources/kafka_servers/kafka_consumer_unique.properties b/kafka-testing/src/test/resources/kafka_servers/kafka_consumer_unique.properties
new file mode 100755
index 00000000..9a954e92
--- /dev/null
+++ b/kafka-testing/src/test/resources/kafka_servers/kafka_consumer_unique.properties
@@ -0,0 +1,33 @@
+# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#          kafka consumer properties
+# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+group.id=consumerGroup_${RANDOM.NUMBER}
+key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
+value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
+max.poll.records=2
+enable.auto.commit=false
+auto.offset.reset=earliest
+
+#
+# -----------------------------
+# client.id is auto generated. Making it unique will have no effect if they belong to same group.
+# Making the group.id as unique makes sense and the new group ca consume same records once again.
+# client.id uniqueness will differentiate from another consumer in the same group.
+# Refer : ConsumerConfig.java in the source code.
+# /kafka/kafka/clients/src/main/java/org/apache/kafka/clients/consumer/ConsumerConfig.java
+# -----------------------------
+#client.id=consumer-1123
+#group.id=None
+#enable.auto.commit=true
+#key.deserializer=org.apache.kafka.common.serialization.LongDeserializer
+#value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
+#
+## fast session timeout makes it more fun to play with failover
+#session.timeout.ms=10000
+#
+## These buffer sizes seem to be needed to avoid consumer switching to
+## a mode where it processes one bufferful every 5 seconds with multiple
+## timeouts along the way.  No idea why this happens.
+#fetch.min.bytes=50000
+#receive.buffer.bytes=262144
+#max.partition.fetch.bytes=2097152
\ No newline at end of file
diff --git a/kafka-testing/src/test/resources/kafka_servers/kafka_producer_unique.properties b/kafka-testing/src/test/resources/kafka_servers/kafka_producer_unique.properties
new file mode 100755
index 00000000..77375892
--- /dev/null
+++ b/kafka-testing/src/test/resources/kafka_servers/kafka_producer_unique.properties
@@ -0,0 +1,19 @@
+# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#          kafka producer properties
+# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+client.id=zerocode-producer_${RANDOM.NUMBER}
+key.serializer=org.apache.kafka.common.serialization.StringSerializer
+value.serializer=org.apache.kafka.common.serialization.StringSerializer
+
+# -------------------------------------------------------------
+# Check in the : ProducerConfig.java file for all list of keys
+# -------------------------------------------------------------
+#acks=all
+#retries=0
+#batch.size=16384
+#client.id=fcd-producer
+#auto.commit.interval.ms=1000
+#linger.ms=0
+#key.serializer=org.apache.kafka.common.serialization.StringSerializer
+#value.serializer=org.apache.kafka.common.serialization.ByteArraySerializer
+#block.on.buffer.full=true
diff --git a/kafka-testing/src/test/resources/kafka_servers/kafka_test_server_unique.properties b/kafka-testing/src/test/resources/kafka_servers/kafka_test_server_unique.properties
new file mode 100755
index 00000000..8597d83d
--- /dev/null
+++ b/kafka-testing/src/test/resources/kafka_servers/kafka_test_server_unique.properties
@@ -0,0 +1,38 @@
+# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+# kafka bootstrap servers comma separated
+# e.g. localhost:9092,host2:9093
+# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+kafka.bootstrap.servers=localhost:9092
+
+kafka.producer.properties=kafka_servers/kafka_producer_unique.properties
+kafka.consumer.properties=kafka_servers/kafka_consumer_unique.properties
+
+# --------------------------------------------------------------------
+# Optional local consumer properties common/central to all test cases.
+# These can be overwritten by the tests locally.
+# --------------------------------------------------------------------
+# If this property is set, then the consumer does a commitSync after reading the message(s)
+# Make sure you don't set both commitSync and commitAsync to true
+consumer.commitSync = true
+# If this property is set, then the consumer does a commitAsync after reading the message(s)
+# Make sure you don't set both commitSync and commitAsync to true
+consumer.commitAsync = false
+# All records those were read are dumped to this specified file path
+# This path can be a relative path or an absolute path. If the file
+# does not exist, it creates the file and dumps the records
+consumer.fileDumpTo= target/temp/demo.txt
+# If this property is set to true, all records are shown in the response.
+# When dealing with large number of records, you might not be interested
+# in the individual records, but interested in the recordCount
+# i.e. total number of records consumed
+consumer.showRecordsConsumed=false
+# That means if any record(s) are read, then this counter is reset to 0(zero) and the consumer
+# polls again. So if no records are fetched for a specific poll interval, then the consumer
+# gives a retry retrying until this max number polls/reties reached.
+consumer.maxNoOfRetryPollsOrTimeouts = 5
+# Polling time in milli seconds i.e how long the consumer should poll before
+# the next retry poll
+consumer.pollingTime = 1000
+
+# local producer properties
+producer.key1=value1-testv ycvb