Repository: authorjapps/zerocode
Pull request #44 (2018-03-05 01:05:00)

ISSUE-43 # Red Spike, Interactive report - Filter by group or author
- And Dashboard etc fancy stuff


Patch:
diff --git a/pom.xml b/pom.xml
index dab88995..e4fad0ef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -70,6 +70,7 @@
         <micro-simulator.version>1.1.10</micro-simulator.version>
         <httpclient.version>4.5</httpclient.version>
         <h2.db.version>1.4.191</h2.db.version>
+        <extentreports.version>3.1.3</extentreports.version>
 
         <!-- maven plugin build related  -->
         <maven-compiler-plugin.version>3.2</maven-compiler-plugin.version>
@@ -198,6 +199,11 @@
             <version>${h2.db.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.aventstack</groupId>
+            <artifactId>extentreports</artifactId>
+            <version>${extentreports.version}</version>
+        </dependency>
     </dependencies>
 
     <profiles>
diff --git a/src/main/java/org/jsmart/zerocode/core/domain/ReportProperties.java b/src/main/java/org/jsmart/zerocode/core/domain/ReportProperties.java
new file mode 100644
index 00000000..7b3d3bc9
--- /dev/null
+++ b/src/main/java/org/jsmart/zerocode/core/domain/ReportProperties.java
@@ -0,0 +1,20 @@
+//package org.jsmart.zerocode.core.domain;
+//
+//import java.lang.annotation.Documented;
+//import java.lang.annotation.ElementType;
+//import java.lang.annotation.Inherited;
+//import java.lang.annotation.Retention;
+//import java.lang.annotation.RetentionPolicy;
+//import java.lang.annotation.Target;
+//
+//@Documented
+//@Target(ElementType.TYPE)
+//@Retention(RetentionPolicy.RUNTIME)
+//@Inherited
+//public @interface ReportProperties {
+//
+//    boolean searchableReport() default true;
+//    boolean filterByAuthor() default true;
+//    boolean spikeReport() default false;
+//
+//}
\ No newline at end of file
diff --git a/src/main/java/org/jsmart/zerocode/core/domain/builders/ExtentReportsFactory.java b/src/main/java/org/jsmart/zerocode/core/domain/builders/ExtentReportsFactory.java
new file mode 100644
index 00000000..01435506
--- /dev/null
+++ b/src/main/java/org/jsmart/zerocode/core/domain/builders/ExtentReportsFactory.java
@@ -0,0 +1,86 @@
+package org.jsmart.zerocode.core.domain.builders;
+
+import com.aventstack.extentreports.ExtentReports;
+import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
+import com.aventstack.extentreports.reporter.configuration.ChartLocation;
+import com.aventstack.extentreports.reporter.configuration.Theme;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+public class ExtentReportsFactory {
+    private static final org.slf4j.Logger LOGGER = getLogger(ExtentReportsFactory.class);
+
+    private static ExtentReports extentReports;
+
+    private static Map<Object, String> systemProperties = new HashMap<>();
+
+    public static ExtentReports createReportTheme(String reportFileName) {
+        ExtentHtmlReporter extentHtmlReporter = createExtentHtmlReporter(reportFileName);
+
+        extentReports = new ExtentReports();
+
+        attachSystemInfo();
+
+        extentReports.attachReporter(extentHtmlReporter);
+        extentReports.setReportUsesManualConfiguration(true);
+
+        return extentReports;
+    }
+
+    public static void attachSystemInfo() {
+        systemProperties = getSystemProperties();
+        final String osName = systemProperties.get("os.name");
+        final String osArchitecture = systemProperties.get("os.arch");
+        final String javaVersion = systemProperties.get("java.version");
+
+        LOGGER.info("Where were the tests fired? Ans: OS:{}, Architecture:{}, Java:{}",
+                osName, osArchitecture, javaVersion);
+
+        extentReports.setSystemInfo("OS : ", osName);
+        extentReports.setSystemInfo("OS Architecture : ", osArchitecture);
+        extentReports.setSystemInfo("Java Version : ", javaVersion);
+    }
+
+    public static ExtentHtmlReporter createExtentHtmlReporter(String reportFileName) {
+        ExtentHtmlReporter extentHtmlReporter = new ExtentHtmlReporter(reportFileName);
+
+        extentHtmlReporter.config().setChartVisibilityOnOpen(false);
+        extentHtmlReporter.config().setTheme(Theme.STANDARD);
+
+        extentHtmlReporter.config().setDocumentTitle("Zerocode Test Report");
+        extentHtmlReporter.config().setReportName("Zerocode Interactive Report");
+        extentHtmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
+
+        return extentHtmlReporter;
+    }
+
+
+    public static Map<Object, String> getSystemProperties() {
+        Map<Object, String> map = new HashMap<>();
+        try {
+            Properties properties = System.getProperties();
+
+            Set sysPropertiesKeys = properties.keySet();
+            for (Object key : sysPropertiesKeys) {
+                map.put(key, properties.getProperty((String) key));
+            }
+
+            // Ask in the community forum who needs and why this Ip information ?
+            /*
+            String ipAddress = InetAddress.getLocalHost().toString();
+            map.put("machine.name", ipAddress.split("/")[0]);
+            map.put("machine.address", ipAddress.split("/")[1]);
+            */
+        } catch (Exception e) {
+            e.printStackTrace();
+            LOGGER.error("Extent reporting error. You can safely ignore this. But to fix this see:" + e);
+        }
+
+        return map;
+    }
+}
diff --git a/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueArrayBuilder.java b/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueArrayBuilder.java
index e4cf4124..34a87373 100644
--- a/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueArrayBuilder.java
+++ b/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueArrayBuilder.java
@@ -8,15 +8,36 @@ import java.util.stream.Collectors;
 
 public class ZeroCodeChartKeyValueArrayBuilder {
 
+    public static final String TEST_FAILED = "FAILED";
+
     List<ZeroCodeChartKeyValue> kvs = new ArrayList<>();
 
     public static ZeroCodeChartKeyValueArrayBuilder newInstance() {
         return new ZeroCodeChartKeyValueArrayBuilder();
     }
 
+    /*
+        var processed_test_result = [{
+            name: 'Will Mock an End Point and Test the end point using Zerocode->setup_mocks',
+            y: 429.0
+        }, {
+            name: 'Will Mock an End Point and Test the end point using Zerocode->actual_test_verify_get_customer',
+            color: '#FF0000',
+            y: 92.0
+        }];
+    */
     public String build() {
         final String dataRowsCommaSeparated = kvs.stream()
-                .map(thisRow -> String.format("['%s',%s]", thisRow.getKey(), thisRow.getValue()))
+                .map(thisRow -> {
+                            if (TEST_FAILED.equals(thisRow.getResult())) {
+                                return String.format("{name: '%s', y: %s, color: '#FF0000'}", thisRow.getKey(), thisRow.getValue());
+                            } else {
+                                return String.format("{name: '%s', y: %s}", thisRow.getKey(), thisRow.getValue());
+                            }
+
+                        }
+
+                )
                 .collect(Collectors.joining(", "));
 
         String dataArray = "[" + dataRowsCommaSeparated + "]";
diff --git a/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueBuilder.java b/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueBuilder.java
index 2e4eb8a4..81500361 100644
--- a/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueBuilder.java
+++ b/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeChartKeyValueBuilder.java
@@ -6,13 +6,14 @@ public class ZeroCodeChartKeyValueBuilder {
 
     String key;
     Double value;
+    String result;
 
     public static ZeroCodeChartKeyValueBuilder newInstance() {
         return new ZeroCodeChartKeyValueBuilder();
     }
 
     public ZeroCodeChartKeyValue build() {
-        ZeroCodeChartKeyValue built = new ZeroCodeChartKeyValue(key, value);
+        ZeroCodeChartKeyValue built = new ZeroCodeChartKeyValue(key, value, result);
         return built;
     }
 
@@ -26,4 +27,9 @@ public class ZeroCodeChartKeyValueBuilder {
         this.value = value;
         return  this;
     }
+
+    public ZeroCodeChartKeyValueBuilder result(String result) {
+        this.result = result;
+        return  this;
+    }
 }
diff --git a/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportProperties.java b/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportProperties.java
index 813f1536..7e752158 100644
--- a/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportProperties.java
+++ b/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportProperties.java
@@ -1,11 +1,13 @@
 package org.jsmart.zerocode.core.domain.reports;
 
 public interface ZeroCodeReportProperties {
+    String TARGET_FILE_NAME = "target/zerocode-interactive.html";
     String TARGET_REPORT_DIR = "target/zerocode-test-reports/";
     String TARGET_FULL_REPORT_DIR = "target/";
     String TARGET_FULL_REPORT_CSV_FILE_NAME = "zerocode_full_report";
     String RESULT_PASS = "PASSED";
     String RESULT_FAIL = "FAILED";
     String HIGH_CHART_HTML_FILE_NAME = "zerocode_results_chart";
+    String AUTHOR_MARKER = "@";
 
 }
diff --git a/src/main/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValue.java b/src/main/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValue.java
index 6365f8db..54bf5324 100644
--- a/src/main/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValue.java
+++ b/src/main/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValue.java
@@ -6,12 +6,15 @@ public class ZeroCodeChartKeyValue {
 
     String key;
     Double value;
+    private String result;
 
     public ZeroCodeChartKeyValue(
             @JsonProperty("key")String key,
-            @JsonProperty("value")Double value) {
+            @JsonProperty("value")Double value,
+            @JsonProperty("result")String result) {
         this.key = key;
         this.value = value;
+        this.result = result;
     }
 
 
@@ -30,4 +33,8 @@ public class ZeroCodeChartKeyValue {
                 ", value=" + value +
                 '}';
     }
+
+    public String getResult() {
+        return result;
+    }
 }
diff --git a/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java b/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java
index 722a9695..a719bb3c 100644
--- a/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java
+++ b/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java
@@ -46,8 +46,8 @@ public class LogCorrelationshipPrinter {
         return this;
     }
 
-    public LogCorrelationshipPrinter result(Boolean passed) {
-        this.result = passed;
+    public LogCorrelationshipPrinter result(Boolean result) {
+        this.result = result;
         return this;
     }
 
@@ -56,6 +56,7 @@ public class LogCorrelationshipPrinter {
         ZeroCodeReportStep zeroCodeReportStep = ZeroCodeReportStepBuilder.newInstance()
                 //.request(requestLogBuilder.request) //TODO
                 //.response(responseLogBuilder.response) //TODO
+                //.assertions()
                 .loop(stepLoop)
                 .name(requestLogBuilder.stepName)
                 .correlationId(correlationId)
diff --git a/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGenerator.java b/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGenerator.java
index 8dc71f5b..6e71fbfb 100644
--- a/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGenerator.java
+++ b/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGenerator.java
@@ -1,7 +1,13 @@
 package org.jsmart.zerocode.core.report;
 
 public interface ZeroCodeReportGenerator {
-    public void generateCsvReport();
+    void generateCsvReport();
 
-    public void generateHighChartReport();
+    /**
+     * Spike chat is disabled by default
+     *
+     */
+    void generateHighChartReport();
+
+    void generateExtentReport();
 }
diff --git a/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java b/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java
index f1b3557d..013db03a 100644
--- a/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java
+++ b/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java
@@ -1,11 +1,16 @@
 package org.jsmart.zerocode.core.report;
 
+import com.aventstack.extentreports.ExtentReports;
+import com.aventstack.extentreports.ExtentTest;
+import com.aventstack.extentreports.Status;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectWriter;
 import com.fasterxml.jackson.dataformat.csv.CsvMapper;
 import com.fasterxml.jackson.dataformat.csv.CsvParser;
 import com.fasterxml.jackson.dataformat.csv.CsvSchema;
 import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import org.jsmart.zerocode.core.domain.builders.ExtentReportsFactory;
 import org.jsmart.zerocode.core.domain.builders.HighChartColumnHtmlBuilder;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeChartKeyValueArrayBuilder;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeChartKeyValueBuilder;
@@ -13,58 +18,131 @@ import org.jsmart.zerocode.core.domain.builders.ZeroCodeCsvReportBuilder;
 import org.jsmart.zerocode.core.domain.reports.ZeroCodeReport;
 import org.jsmart.zerocode.core.domain.reports.chart.HighChartColumnHtml;
 import org.jsmart.zerocode.core.domain.reports.csv.ZeroCodeCsvReport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import static java.util.Collections.emptyList;
 import static java.util.Optional.ofNullable;
+import static org.apache.commons.lang.StringUtils.substringBetween;
+import static org.jsmart.zerocode.core.domain.reports.ZeroCodeReportProperties.AUTHOR_MARKER;
+import static org.jsmart.zerocode.core.domain.reports.ZeroCodeReportProperties.RESULT_PASS;
+import static org.jsmart.zerocode.core.domain.reports.ZeroCodeReportProperties.TARGET_FILE_NAME;
 import static org.jsmart.zerocode.core.domain.reports.ZeroCodeReportProperties.TARGET_FULL_REPORT_CSV_FILE_NAME;
 import static org.jsmart.zerocode.core.domain.reports.ZeroCodeReportProperties.TARGET_FULL_REPORT_DIR;
 import static org.jsmart.zerocode.core.domain.reports.ZeroCodeReportProperties.TARGET_REPORT_DIR;
 
 public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ZeroCodeReportGeneratorImpl.class);
+
+    /**
+     * Spike chat is disabled by default
+     */
+    @Inject(optional = true)
+    @Named("report.spike.chart.enabled")
+    private boolean spikeChartReportEnabled;
 
     @Inject
     private ObjectMapper mapper;
 
-    private List<ZeroCodeReport> individualReports;
+    private List<ZeroCodeReport> treeReports;
 
-    private List<ZeroCodeCsvReport> csvRows = new ArrayList<>();
+    private List<ZeroCodeCsvReport> zeroCodeCsvFlattenedRows;
 
-    private List<ZeroCodeCsvReport> zeroCodeCsvReportRows;
+    private List<ZeroCodeCsvReport> csvRows = new ArrayList<>();
 
     public ZeroCodeReportGeneratorImpl() {
     }
 
+    @Override
+    public void generateExtentReport() {
+
+        ExtentReports extentReports = ExtentReportsFactory.createReportTheme(TARGET_FILE_NAME);
+
+        treeReports.forEach(thisReport -> {
+
+            thisReport.getResults().forEach(thisScenario -> {
+                ExtentTest test = extentReports.createTest(thisScenario.getScenarioName());
+                test.assignCategory("Regression"); //Read this from POM file //TODO
+
+                test.assignAuthor(optionalAuthor(thisScenario.getScenarioName()));
+
+                thisScenario.getSteps().forEach(thisStep -> {
+                    test.getModel().setStartTime(utilDateOf(thisStep.getRequestTimeStamp()));
+                    test.getModel().setEndTime(utilDateOf(thisStep.getResponseTimeStamp()));
+
+                    final Status testStatus = thisStep.getResult().equals(RESULT_PASS) ? Status.PASS : Status.FAIL;
+                    test.createNode(thisStep.getName(), "CORRELATION-ID: "
+                            + thisStep.getCorrelationId()).log(testStatus, thisStep.getName()
+                            + " has " + thisStep.getResult()
+                            + ". \n Search in the log file for-  CORRELATION-ID:  \n"
+                            + thisStep.getCorrelationId() + "\n"
+                            + ", url:" + thisStep.getUrl() + "\n"
+                    );
+
+                    extentReports.flush();
+                });
+
+            });
+
+        });
+    }
+
+    protected String optionalAuthor(String scenarioName) {
+        String authorName = substringBetween(scenarioName, AUTHOR_MARKER, AUTHOR_MARKER);
+
+        if(authorName == null){
+            authorName = substringBetween(scenarioName, AUTHOR_MARKER, " ");
+        }
+
+        if(authorName == null){
+            authorName = scenarioName.substring(scenarioName.lastIndexOf(AUTHOR_MARKER) + 1);
+        }
+
+        if(scenarioName.lastIndexOf(AUTHOR_MARKER) == -1 || authorName == null){
+            authorName = "Unknown-Author";
+        }
+
+        return authorName;
+    }
+
     @Override
     public void generateCsvReport() {
         /*
          * Read individual reports for aggregation
          */
-        individualReports = readZeroCodeReportsByPath(TARGET_REPORT_DIR);
+        treeReports = readZeroCodeReportsByPath(TARGET_REPORT_DIR);
 
         /*
          * Generate: CSV report
          */
-        zeroCodeCsvReportRows = buildCsvRows();
-        generateCsvReport(zeroCodeCsvReportRows);
+        zeroCodeCsvFlattenedRows = buildCsvRows();
+        generateCsvReport(zeroCodeCsvFlattenedRows);
     }
 
     @Override
     public void generateHighChartReport() {
+        LOGGER.info("####spikeChartReportEnabled: " + spikeChartReportEnabled);
+
         /*
          * Generate: Chart using HighChart
          */
-        HighChartColumnHtml highChartColumnHtml = convertCsvRowsToHighChartData(zeroCodeCsvReportRows);
-        generateHighChartReport(highChartColumnHtml);
+        if(spikeChartReportEnabled){
+            HighChartColumnHtml highChartColumnHtml = convertCsvRowsToHighChartData(zeroCodeCsvFlattenedRows);
+            generateHighChartReport(highChartColumnHtml);
+        }
     }
 
+
     private HighChartColumnHtml convertCsvRowsToHighChartData(List<ZeroCodeCsvReport> zeroCodeCsvReportRows) {
 
         //TODO: read from the property file. Inject as fields.
@@ -80,6 +158,7 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
                 dataArrayBuilder.kv(ZeroCodeChartKeyValueBuilder.newInstance()
                         .key(thisRow.getScenarioName() + "->" + thisRow.getStepName())
                         .value(thisRow.getResponseDelayMilliSec())
+                        .result(thisRow.getResult())
                         .build())
         );
 
@@ -139,7 +218,7 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
          */
         ZeroCodeCsvReportBuilder csvFileBuilder = ZeroCodeCsvReportBuilder.newInstance();
 
-        individualReports.forEach(thisReport ->
+        treeReports.forEach(thisReport ->
                 thisReport.getResults().forEach(thisResult -> {
 
                     csvFileBuilder.scenarioLoop(thisResult.getLoop());
@@ -227,4 +306,7 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
 
     }
 
+    private static Date utilDateOf(LocalDateTime localDateTime) {
+        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
+    }
 }
diff --git a/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java b/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
index 94419a59..20486223 100644
--- a/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
+++ b/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
@@ -3,17 +3,6 @@ package org.jsmart.zerocode.core.runner;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.util.Modules;
-
-import org.jsmart.zerocode.core.domain.EnvProperty;
-import org.jsmart.zerocode.core.engine.listener.ZeroCodeTestReportListener;
-import org.junit.runner.Description;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.BlockJUnit4ClassRunner;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.InitializationError;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.jsmart.zerocode.core.di.ApplicationMainModule;
 import org.jsmart.zerocode.core.di.RuntimeHttpClientModule;
 import org.jsmart.zerocode.core.domain.HostProperties;
@@ -21,20 +10,25 @@ import org.jsmart.zerocode.core.domain.JsonTestCase;
 import org.jsmart.zerocode.core.domain.ScenarioSpec;
 import org.jsmart.zerocode.core.domain.TargetEnv;
 import org.jsmart.zerocode.core.domain.UseHttpClient;
+import org.jsmart.zerocode.core.engine.listener.ZeroCodeTestReportListener;
 import org.jsmart.zerocode.core.httpclient.BasicHttpClient;
 import org.jsmart.zerocode.core.httpclient.RestEasyDefaultHttpClient;
 import org.jsmart.zerocode.core.report.ZeroCodeReportGenerator;
 import org.jsmart.zerocode.core.utils.SmartUtils;
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.stream.Collectors;
 
 import static org.jsmart.zerocode.core.utils.RunnerUtils.getEnvSpecificConfigFile;
-import static org.jsmart.zerocode.core.utils.SmartUtils.getAllTokens;
-import static org.jsmart.zerocode.core.utils.SmartUtils.getEnvPropertyValue;
 
 public class ZeroCodeUnitRunner extends BlockJUnit4ClassRunner {
     private static final Logger LOGGER = LoggerFactory.getLogger(ZeroCodeUnitRunner.class);
@@ -174,7 +168,7 @@ public class ZeroCodeUnitRunner extends BlockJUnit4ClassRunner {
     }
 
     public Injector getMainModuleInjector() {
-        // TODO: Synchronise this with an object lock e.g. synchronized (IptSmartRunner.class) {}
+        // TODO: Synchronise this with an object lock e.g. synchronized (ZeroCodeUnitRunner.class) {}
         final TargetEnv envAnnotation = testClass.getAnnotation(TargetEnv.class);
         String serverEnv = envAnnotation != null ? envAnnotation.value() : "config_hosts.properties";
 
diff --git a/src/main/resources/reports/01_high_chart_column.vm b/src/main/resources/reports/01_high_chart_column.vm
index a90a1352..01f32a89 100644
--- a/src/main/resources/reports/01_high_chart_column.vm
+++ b/src/main/resources/reports/01_high_chart_column.vm
@@ -16,12 +16,26 @@
     <script type="text/javascript">
         $(function () {
 
+## OLD - Only 1 color-
 ##            var processed_test_result = [
 ##                ['Test Case -> Step1',1],
 ##                ['Test Case -> Step2',10],
 ##                ['Test Case -> Step3', 5]
 ##            ];
 
+## NEW - Red color for failed tests-
+## See example: https://www.highcharts.com/docs/chart-concepts/series
+## and test in JSFiddle: http://jsfiddle.net/awsLL5sx/1/
+##
+##           var processed_test_result = [{
+##               name: 'Will Mock an End Point and Test the end point using Zerocode->setup_mocks',
+##               y: 429.0
+##           }, {
+##               name: 'Will Mock an End Point and Test the end point using Zerocode->actual_test_verify_get_customer',
+##               color: '#FF0000',
+##               y: 92.0
+##           }];
+
             var processed_test_result = $highChartColumnHtml.testResult;
             $(function () {
 


Test patch:
diff --git a/src/main/java/org/jsmart/zerocode/core/engine/listener/ZeroCodeTestReportListener.java b/src/main/java/org/jsmart/zerocode/core/engine/listener/ZeroCodeTestReportListener.java
index c2460c59..966d1a74 100644
--- a/src/main/java/org/jsmart/zerocode/core/engine/listener/ZeroCodeTestReportListener.java
+++ b/src/main/java/org/jsmart/zerocode/core/engine/listener/ZeroCodeTestReportListener.java
@@ -40,15 +40,16 @@ public class ZeroCodeTestReportListener extends RunListener {
          */
         LOGGER.info("### ZeroCode: all testRunFinished. Generating test reports and charts");
 
-        generateCharts();
+        generateChartsAndReports();
 
     }
 
-    private void generateCharts() {
+    private void generateChartsAndReports() {
 
         reportGenerator.generateCsvReport();
 
-        reportGenerator.generateHighChartReport();
+        reportGenerator.generateExtentReport();
 
+        reportGenerator.generateHighChartReport();
     }
 }
\ No newline at end of file
diff --git a/src/test/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValueTest.java b/src/test/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValueTest.java
index 296eb70a..187a4741 100644
--- a/src/test/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValueTest.java
+++ b/src/test/java/org/jsmart/zerocode/core/domain/reports/chart/ZeroCodeChartKeyValueTest.java
@@ -10,6 +10,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import static javax.management.remote.JMXConnectionNotification.FAILED;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -21,24 +22,27 @@ public class ZeroCodeChartKeyValueTest {
     public void serialize() throws Exception {
 
         ZeroCodeChartKeyValue kv1 = ZeroCodeChartKeyValueBuilder.newInstance().key("Scenario 1: Step1").value(100D).build();
-        ZeroCodeChartKeyValue kv2 = ZeroCodeChartKeyValueBuilder.newInstance().key("Scenario 2: Step2").value(500D).build();
+        ZeroCodeChartKeyValue kv2 = ZeroCodeChartKeyValueBuilder.newInstance().key("Scenario 2: Step2").value(500D).result(ZeroCodeChartKeyValueArrayBuilder.TEST_FAILED).build();
 
         List<ZeroCodeChartKeyValue> kvs = Arrays.asList(kv1, kv2);
 
         final String jsonString = mapper.writeValueAsString(kvs);
 
-        assertThat(jsonString, containsString("{\"key\":\"Scenario 2: Step2\",\"value\":500.0}"));
+        assertThat(jsonString, containsString("[{\"key\":\"Scenario 1: Step1\",\"value\":100.0,\"result\":null},{\"key\":\"Scenario 2: Step2\",\"value\":500.0,\"result\":\"FAILED\"}]"));
 
     }
 
     @Test
     public void willGenertaeCommaSeparatedKV() throws Exception {
         /*
-                var myArray = [
-                ['Test Scenario1 -> Step1',1],
-                ['Test Scenario2 -> Step2',10],
-                ['Test Scenario3 -> Step3', 5]
-                ];
+           var processed_result_array = [{
+               name: 'Scenario 1 -> Step no.1',
+               y: 429.0
+           }, {
+               name: name: 'Scenario 2 -> Step no.2',
+               color: '#FF0000',
+               y: 92.0
+           }];
         */
 
         ZeroCodeChartKeyValue kv1 = ZeroCodeChartKeyValueBuilder.newInstance().key("Scenario 1: Step1").value(100D).build();
@@ -55,13 +59,13 @@ public class ZeroCodeChartKeyValueTest {
         assertThat(dataArray, is("[['Scenario 1: Step1',100.0], ['Scenario 2: Step2',500.0]]"));
 
         String kvArray = ZeroCodeChartKeyValueArrayBuilder.newInstance().kvs(kvs).build();
-        assertThat(kvArray, is("[['Scenario 1: Step1',100.0], ['Scenario 2: Step2',500.0]]"));
+        assertThat(kvArray, is("[{name: 'Scenario 1: Step1', y: 100.0}, {name: 'Scenario 2: Step2', y: 500.0}]"));
 
         String kvArrayAgain = ZeroCodeChartKeyValueArrayBuilder.newInstance()
                 .kv(kv1)
                 .kv(kv2)
                 .build();
-        assertThat(kvArrayAgain, is("[['Scenario 1: Step1',100.0], ['Scenario 2: Step2',500.0]]"));
+        assertThat(kvArrayAgain, is("[{name: 'Scenario 1: Step1', y: 100.0}, {name: 'Scenario 2: Step2', y: 500.0}]"));
 
     }
 }
\ No newline at end of file
diff --git a/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java b/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java
index 1699708a..51d931f0 100644
--- a/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java
+++ b/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java
@@ -6,6 +6,9 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+
 public class ZeroCodeReportGeneratorImplTest {
 
     @Rule
@@ -42,4 +45,28 @@ public class ZeroCodeReportGeneratorImplTest {
         zeroCodeReportGenerator.validateReportsFolderAndTheFilesExists(reportsFolder);
 
     }
+
+    @Test
+    public void testAuthorJiraStyle() throws Exception {
+        String author;
+        author = zeroCodeReportGenerator.optionalAuthor("PayPal One touch payment @Peter@");
+        assertThat(author, is("Peter"));
+
+        author = zeroCodeReportGenerator.optionalAuthor("PayPal One touch @payment @Peter@");
+        assertThat(author, is("payment "));
+
+        author = zeroCodeReportGenerator.optionalAuthor("PayPal One touch payment @Peter Gibson@");
+        assertThat(author, is("Peter Gibson"));
+
+        author = zeroCodeReportGenerator.optionalAuthor("PayPal One touch payment @Peter Gibson");
+        assertThat(author, is("Peter"));
+
+        author = zeroCodeReportGenerator.optionalAuthor("PayPal One touch payment @Peter");
+        assertThat(author, is("Peter"));
+
+        author = zeroCodeReportGenerator.optionalAuthor("PayPal One touch payment");
+        assertThat(author, is("Unknown-Author"));
+
+    }
+
 }
\ No newline at end of file
diff --git a/src/test/resources/soap_host.properties b/src/test/resources/soap_host.properties
index 1f96a583..f33b6de7 100755
--- a/src/test/resources/soap_host.properties
+++ b/src/test/resources/soap_host.properties
@@ -4,3 +4,6 @@ restful.application.endpoint.port=80
 
 # Google Map Service Context
 restful.application.endpoint.context=
+
+# This is false by default, it runs even if this property is not present here
+report.spike.chart.enabled=true
\ No newline at end of file