Repository: authorjapps/zerocode
Pull request #390 (2020-05-08 17:21:22)

ISSUE-389 # fix retry report issue
# fix retry issue

PR Branch
**https://github.com/sparrowV/zerocode**

## Motivation and Context

## Checklist:

* [x] Unit tests added?

* [ ] Integration tests added?

* [x] Test names are meaningful?

* [x] Feature manually tested?

* [x] Branch build passed?

* [x] No 'package.*' in the imports

* [ ] Relevant Wiki page updated with clear instruction for the end user

* [ ] Http test added to `http-testing` module(if applicable) ?

* [ ] Kafka test added to `kafka-testing` module(if applicable) ?



Patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeExecResult.java b/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeExecResult.java
index faab8c7d..ae17016b 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeExecResult.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeExecResult.java
@@ -35,6 +35,10 @@ public class ZeroCodeExecResult {
         return steps;
     }
 
+    public void setSteps(List<ZeroCodeReportStep> steps) {
+        this.steps = steps;
+    }
+
     @Override
     public String toString() {
         return "ZeroCodeExecResult{" +
diff --git a/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportStep.java b/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportStep.java
index ddfb08fd..07d6c6f2 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportStep.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/domain/reports/ZeroCodeReportStep.java
@@ -61,6 +61,12 @@ public class ZeroCodeReportStep {
         this.customLog = customLog;
     }
 
+
+    public  ZeroCodeReportStep(String correlationId,String result){
+        this(null,null,null,null,correlationId,null,null,null,null,result,null,null,null,null);
+    }
+
+
     public Integer getLoop() {
         return loop;
     }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java
index dc3e6cc9..bd5b6668 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImpl.java
@@ -18,7 +18,9 @@ import org.jsmart.zerocode.core.domain.builders.HighChartColumnHtmlBuilder;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeChartKeyValueArrayBuilder;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeChartKeyValueBuilder;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeCsvReportBuilder;
+import org.jsmart.zerocode.core.domain.reports.ZeroCodeExecResult;
 import org.jsmart.zerocode.core.domain.reports.ZeroCodeReport;
+import org.jsmart.zerocode.core.domain.reports.ZeroCodeReportStep;
 import org.jsmart.zerocode.core.domain.reports.chart.HighChartColumnHtml;
 import org.jsmart.zerocode.core.domain.reports.csv.ZeroCodeCsvReport;
 import org.slf4j.Logger;
@@ -28,10 +30,7 @@ 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.*;
 import java.util.stream.Collectors;
 
 import static java.util.Collections.emptyList;
@@ -82,10 +81,26 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
         this.mapper = mapper;
     }
 
+    /**
+     * Gets unique steps from a scenario. In case of retries, the steps have same correlation id and if
+     * one of the retries is successful, we include it in the result(not the one which failed).
+     * In a normal case(without retry), both PASS and FAIL will be included as usual.
+     * @param steps
+     * @return
+     */
+     List<ZeroCodeReportStep> getUniqueSteps(List<ZeroCodeReportStep> steps){
+        Map<String,ZeroCodeReportStep> result = new HashMap<>();
+        steps.forEach(step->{
+            result.merge(step.getCorrelationId(), step,
+                    (s1, s2) -> RESULT_PASS.equals(s1.getResult()) ? s1 : s2);
+        });
+        return new ArrayList<>(result.values());
+    }
+
     @Override
     public void generateExtentReport() {
 
-        if(interactiveHtmlReportDisabled){
+        if (interactiveHtmlReportDisabled) {
             return;
         }
 
@@ -100,22 +115,22 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
                 test.assignCategory(DEFAULT_REGRESSION_CATEGORY);
 
                 test.assignAuthor(optionalAuthor(thisScenario.getScenarioName()));
-
-                thisScenario.getSteps().forEach(thisStep -> {
+                List<ZeroCodeReportStep> thisScenarioUniqueSteps = getUniqueSteps(thisScenario.getSteps());
+                thisScenarioUniqueSteps.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;
-					
+
                     ExtentTest step = test.createNode(thisStep.getName(), TEST_STEP_CORRELATION_ID + " " + thisStep.getCorrelationId());
-                 
-                    if(testStatus.equals(Status.PASS)) {
-                    	step.pass(thisStep.getResult());
-                    }else {
-                    	step.info(MarkupHelper.createCodeBlock(thisStep.getOperation() + "\t" + thisStep.getUrl()));
-                    	step.info(MarkupHelper.createCodeBlock(thisStep.getRequest(), CodeLanguage.JSON));
+
+                    if (testStatus.equals(Status.PASS)) {
+                        step.pass(thisStep.getResult());
+                    } else {
+                        step.info(MarkupHelper.createCodeBlock(thisStep.getOperation() + "\t" + thisStep.getUrl()));
+                        step.info(MarkupHelper.createCodeBlock(thisStep.getRequest(), CodeLanguage.JSON));
                         step.info(MarkupHelper.createCodeBlock(thisStep.getResponse(), CodeLanguage.JSON));
-                    	step.fail(MarkupHelper.createCodeBlock("Reason:\n" + thisStep.getAssertions()));
+                        step.fail(MarkupHelper.createCodeBlock("Reason:\n" + thisStep.getAssertions()));
                     }
                     extentReports.flush();
                 });
@@ -133,13 +148,13 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
         // (might be disabled by current runner)
         // Then it's good to link it to that spike report.
         // ------------------------------------------------
-        if(spikeChartReportEnabled || spikeChartFileName != null){
+        if (spikeChartReportEnabled || spikeChartFileName != null) {
             final String reportName = getReportName();
 
             String linkCodeToTargetSpikeChartHtml =
                     String.format("<code>&nbsp;&nbsp;<a href='%s' style=\"color: #006; background: #ff6;\"> %s </a></code>",
-                    spikeChartFileName,
-                    LINK_LABEL_NAME);
+                            spikeChartFileName,
+                            LINK_LABEL_NAME);
 
             ExtentReportsFactory.reportName(reportName + linkCodeToTargetSpikeChartHtml);
         }
@@ -148,33 +163,33 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
     protected String optionalAuthor(String scenarioName) {
         String authorName = substringBetween(scenarioName, AUTHOR_MARKER, AUTHOR_MARKER);
 
-        if(authorName == null){
+        if (authorName == null) {
             authorName = substringBetween(scenarioName, AUTHOR_MARKER, ",");
         }
 
-        if(authorName == null){
+        if (authorName == null) {
             authorName = substringBetween(scenarioName, AUTHOR_MARKER, " ");
         }
 
-        if(authorName == null){
+        if (authorName == null) {
             authorName = scenarioName.substring(scenarioName.lastIndexOf(AUTHOR_MARKER) + AUTHOR_MARKER.length());
         }
 
-        if(scenarioName.lastIndexOf(AUTHOR_MARKER) == -1 || StringUtils.isEmpty(authorName)){
+        if (scenarioName.lastIndexOf(AUTHOR_MARKER) == -1 || StringUtils.isEmpty(authorName)) {
             authorName = ANONYMOUS_AUTHOR;
         }
 
         return authorName;
     }
-    
+
     protected String onlyScenarioName(String scenarioName) {
-    	
-    	int index = scenarioName.indexOf(AUTHOR_MARKER);
-    	if(index == -1) {
-    		return scenarioName;
-    	}else {
-    		return scenarioName.substring(0, index -1); 
-    	}
+
+        int index = scenarioName.indexOf(AUTHOR_MARKER);
+        if (index == -1) {
+            return scenarioName;
+        } else {
+            return scenarioName.substring(0, index - 1);
+        }
     }
 
     @Override
@@ -198,7 +213,7 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
         /*
          * Generate: Spike Chart using HighChart
          */
-        if(spikeChartReportEnabled){
+        if (spikeChartReportEnabled) {
             HighChartColumnHtml highChartColumnHtml = convertCsvRowsToHighChartData(zeroCodeCsvFlattenedRows);
             generateHighChartReport(highChartColumnHtml);
         }
@@ -331,7 +346,11 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
                     }
                 })
                 .collect(Collectors.toList());
-
+        for (ZeroCodeReport zeroCodeReport : scenarioReports) {
+            for (ZeroCodeExecResult zeroCodeExecResult : zeroCodeReport.getResults()) {
+                zeroCodeExecResult.setSteps(getUniqueSteps(zeroCodeExecResult.getSteps()));
+            }
+        }
         return scenarioReports;
     }
 
@@ -342,7 +361,7 @@ public class ZeroCodeReportGeneratorImpl implements ZeroCodeReportGenerator {
             return name.endsWith(".json");
         });
 
-        if(files == null || files.length == 0){
+        if (files == null || files.length == 0) {
 
             LOGGER.error("\n\t\t\t************\nNow files were found in folder:{}, hence could not proceed. " +
                     "\n(If this was intentional, then you can safely ignore this error)" +


Test patch:
diff --git a/core/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java b/core/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java
index b05c464f..469272bc 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/report/ZeroCodeReportGeneratorImplTest.java
@@ -2,14 +2,21 @@ package org.jsmart.zerocode.core.report;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.jsmart.zerocode.core.di.provider.ObjectMapperProvider;
+import org.jsmart.zerocode.core.domain.reports.ZeroCodeReportStep;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
+import static org.jsmart.zerocode.core.constants.ZeroCodeReportConstants.RESULT_FAIL;
+import static org.jsmart.zerocode.core.constants.ZeroCodeReportConstants.RESULT_PASS;
+import static org.junit.Assert.assertEquals;
 
 public class ZeroCodeReportGeneratorImplTest {
 
@@ -76,4 +83,38 @@ public class ZeroCodeReportGeneratorImplTest {
 
     }
 
+    @Test
+    public void testGettingUniqueStepsForMultipleRetries(){
+        List<ZeroCodeReportStep> steps = new ArrayList<ZeroCodeReportStep>(){
+            {
+                add(new ZeroCodeReportStep("testCorrelationId",RESULT_PASS));
+                add(new ZeroCodeReportStep("testCorrelationId",RESULT_FAIL));
+            }
+        };
+        List<ZeroCodeReportStep> uniqueSteps = zeroCodeReportGenerator.getUniqueSteps(steps);
+        assertEquals(uniqueSteps.size() , 1);
+        assertEquals(uniqueSteps.get(0).getResult(),RESULT_PASS);
+    }
+
+    @Test
+    public void testGettingUniqueStepsForNoRetries(){
+        List<ZeroCodeReportStep> steps = new ArrayList<ZeroCodeReportStep>(){
+            {
+                add(new ZeroCodeReportStep("testCorrelationId1",RESULT_PASS));
+                add(new ZeroCodeReportStep("testCorrelationId2",RESULT_FAIL));
+                add(new ZeroCodeReportStep("testCorrelationId3",RESULT_FAIL));
+            }
+        };
+        List<ZeroCodeReportStep> uniqueSteps = zeroCodeReportGenerator.getUniqueSteps(steps);
+        assertEquals(uniqueSteps.size() , 3);
+        assertEquals(uniqueSteps.stream().filter(step->step.getResult().equals(RESULT_PASS)).count(),1);
+        assertEquals(uniqueSteps.stream().filter(step->step.getResult().equals(RESULT_FAIL)).count(),2);
+
+        assertThat(uniqueSteps.get(0).getCorrelationId(),is("testCorrelationId3")); // order different to original
+        assertThat(uniqueSteps.get(1).getCorrelationId(),is("testCorrelationId1")); // order different to original
+        assertThat(uniqueSteps.get(2).getCorrelationId(),is("testCorrelationId2")); // order different to original
+
+        // order different to original: Not really an issue, as the CSV can be sorted ACS or DESC by a an external tool
+    }
+
 }
\ No newline at end of file