Repository: authorjapps/zerocode
Pull request #225 (2019-03-24 09:14:45)

ZeroCode-224   Step externalisation


Patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/domain/Step.java b/core/src/main/java/org/jsmart/zerocode/core/domain/Step.java
index a34ef98a..0a74c0f4 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/domain/Step.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/domain/Step.java
@@ -18,7 +18,8 @@ public class Step {
     private final String url;
     private JsonNode request;
     private JsonNode assertions;
-
+    private String id;
+    private JsonNode stepFile;
 
     public Integer getLoop() {
         return loop;
@@ -44,6 +45,22 @@ public class Step {
         return assertions;
     }
 
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public JsonNode getStepFile() {
+        return stepFile;
+    }
+
+    public void setStepFile(JsonNode stepFile) {
+        this.stepFile = stepFile;
+    }
+
     @JsonCreator
     public Step(
             @JsonProperty("stepLoop") Integer loop,
@@ -51,7 +68,8 @@ public class Step {
             @JsonProperty("operation") String operation,
             @JsonProperty("url") String url,
             @JsonProperty("request") JsonNode request,
-            @JsonProperty("assertions") JsonNode assertions) {
+            @JsonProperty("assertions") JsonNode assertions
+    ) {
         this.loop = loop;
         this.name = name;
         this.operation = operation;
@@ -63,12 +81,14 @@ public class Step {
     @Override
     public String toString() {
         return "Step{" +
-                "stepLoop=" + loop +
+                "loop=" + loop +
                 ", name='" + name + '\'' +
                 ", operation='" + operation + '\'' +
                 ", url='" + url + '\'' +
                 ", request=" + request +
                 ", assertions=" + assertions +
+                ", id='" + id + '\'' +
+                ", stepFile=" + stepFile +
                 '}';
     }
 }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeReportStepBuilder.java b/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeReportStepBuilder.java
index 34d4ea13..70e2fff5 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeReportStepBuilder.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeReportStepBuilder.java
@@ -16,6 +16,7 @@ public class ZeroCodeReportStepBuilder {
     String result;
     String request;
     String response;
+    String id;
 
     public static ZeroCodeReportStepBuilder newInstance() {
         return new ZeroCodeReportStepBuilder();
@@ -85,4 +86,9 @@ public class ZeroCodeReportStepBuilder {
         return this;
     }
 
+    public ZeroCodeReportStepBuilder id(String id) {
+        this.id = id;
+        return this;
+    }
+
 }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java b/core/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java
index 9777dab1..a23f1adb 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/logbuilder/LogCorrelationshipPrinter.java
@@ -26,6 +26,7 @@ public class LogCorrelationshipPrinter {
     private Boolean result;
     private Double responseDelay;
 
+
     public LogCorrelationshipPrinter(Logger logger) {
         this.logger = logger;
     }
@@ -70,7 +71,8 @@ public class LogCorrelationshipPrinter {
                 .result(responseLogBuilder.getAssertion())
                 .requestTimeStamp(requestLogBuilder.getRequestTimeStamp())
                 .responseTimeStamp(responseLogBuilder.responseTimeStamp)
-                .responseDelay(responseDelay);
+                .responseDelay(responseDelay)
+                .id(requestLogBuilder.getId());
         if (this.result) {
         	zeroCodeReportStep.result(RESULT_PASS);
 		}else{
diff --git a/core/src/main/java/org/jsmart/zerocode/core/logbuilder/RequestLogBuilder.java b/core/src/main/java/org/jsmart/zerocode/core/logbuilder/RequestLogBuilder.java
index 9fae01db..ede1a4f2 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/logbuilder/RequestLogBuilder.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/logbuilder/RequestLogBuilder.java
@@ -13,6 +13,8 @@ public class RequestLogBuilder {
     private String request;
     private String stepName;
     private Integer loop;
+    private String id;
+
 
     @JsonCreator
     public RequestLogBuilder() {
@@ -53,6 +55,12 @@ public class RequestLogBuilder {
         return this;
     }
 
+    public RequestLogBuilder id(String id){
+        this.id = id;
+        return this;
+    }
+
+
     public LocalDateTime getRequestTimeStamp() {
         return requestTimeStamp;
     }
@@ -81,11 +89,22 @@ public class RequestLogBuilder {
         return loop;
     }
 
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+
+
     @Override
     public String toString() {
         return relationshipId +
                 "\n*requestTimeStamp:" + requestTimeStamp +
                 "\nstep:" + stepName +
+                "\nid:" + id +
                 "\nurl:" + url +
                 "\nmethod:" + method +
                 "\nrequest:\n" + request;
diff --git a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java
index d5f53793..83c987a2 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java
@@ -1,8 +1,11 @@
 package org.jsmart.zerocode.core.runner;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.google.inject.name.Named;
+import org.jsmart.zerocode.core.di.provider.ObjectMapperProvider;
 import org.jsmart.zerocode.core.domain.ScenarioSpec;
 import org.jsmart.zerocode.core.domain.Step;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeExecResultBuilder;
@@ -36,6 +39,8 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
 
     private static final Logger LOGGER = getLogger(ZeroCodeMultiStepsScenarioRunnerImpl.class);
 
+    private final ObjectMapper objectMapper = new ObjectMapperProvider().get();
+
     @Inject
     private ZeroCodeJsonTestProcesor zeroCodeJsonTestProcesor;
 
@@ -57,14 +62,10 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
     @Named("web.application.endpoint.context")
     private String applicationContext;
 
-    //---------------------------------------------------
-    //kafka bootstrap servers or brokers comma separated
-    //---------------------------------------------------
     @Inject(optional = true)
     @Named("kafka.bootstrap.servers")
     private String kafkaServers;
 
-
     //guice -ends
 
     private LogCorrelationshipPrinter logCorrelationshipPrinter;
@@ -109,6 +110,10 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
 
                     thisStep = extFileProcessor.resolveExtJsonFile(thisStep);
 
+                    String stepId = thisStep.getId();
+
+                    thisStep = createFromStepFile(thisStep, stepId);
+
                     final String requestJsonAsString = thisStep.getRequest().toString();
 
                     StepExecutionState stepExecutionState = new StepExecutionState();
@@ -154,6 +159,7 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
                                         .step(thisStepName)
                                         .url(serviceName)
                                         .method(operationName)
+                                        .id(stepId)
                                         .request(prettyPrintJson(resolvedRequestJson));
 
                                 executionResult = serviceExecutor.executeRESTService(serviceName, operationName, resolvedRequestJson);
@@ -165,6 +171,7 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
                                         .relationshipId(logPrefixRelationshipId)
                                         .requestTimeStamp(requestTimeStamp)
                                         .step(thisStepName)
+                                        .id(stepId)
                                         .url(serviceName)
                                         .method(operationName)
                                         .request(prettyPrintJson(resolvedRequestJson));
@@ -173,7 +180,7 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
                                 break;
 
                             case KAFKA_CALL:
-                                if(kafkaServers == null){
+                                if (kafkaServers == null) {
                                     throw new RuntimeException(">>> 'kafka.bootstrap.servers' property can not be null for kafka operations");
                                 }
                                 printBrokerProperties();
@@ -184,6 +191,7 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
                                         .step(thisStepName)
                                         .url(serviceName)
                                         .method(operationName)
+                                        .id(stepId)
                                         .request(prettyPrintJson(resolvedRequestJson));
 
                                 String topicName = serviceName.substring(KAFKA_TOPIC.length());
@@ -196,6 +204,7 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
                                         .relationshipId(logPrefixRelationshipId)
                                         .requestTimeStamp(requestTimeStamp)
                                         .step(thisStepName)
+                                        .id(stepId)
                                         .url(serviceName)
                                         .method(operationName)
                                         .request(prettyPrintJson(resolvedRequestJson));
@@ -231,19 +240,21 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
                         List<JsonAsserter> asserters = zeroCodeJsonTestProcesor.createAssertersFrom(resolvedAssertionJson);
                         List<AssertionReport> failureResults = zeroCodeJsonTestProcesor.assertAllAndReturnFailed(asserters, executionResult);
 
-                        if(!failureResults.isEmpty()) {
-                        	StringBuilder builder = new StringBuilder();
-                        	failureResults.forEach(f -> { builder.append(f.toString() + "\n"); });
-                        	logCorrelationshipPrinter.assertion(builder.toString());
-                        }else {
-                        	
-                        	logCorrelationshipPrinter.assertion(prettyPrintJson(resolvedAssertionJson));
+                        if (!failureResults.isEmpty()) {
+                            StringBuilder builder = new StringBuilder();
+                            failureResults.forEach(f -> {
+                                builder.append(f.toString() + "\n");
+                            });
+                            logCorrelationshipPrinter.assertion(builder.toString());
+                        } else {
+
+                            logCorrelationshipPrinter.assertion(prettyPrintJson(resolvedAssertionJson));
                         }
                         // --------------------------------------------------------------------------------
                         // Non dependent requests into a single JSON file (Issue-167 - Feature Implemented)
                         // --------------------------------------------------------------------------------
-                        boolean ignoreStepFailures = scenario.getIgnoreStepFailures() == null? false : scenario.getIgnoreStepFailures();
-                        if(ignoreStepFailures == true && !failureResults.isEmpty()){
+                        boolean ignoreStepFailures = scenario.getIgnoreStepFailures() == null ? false : scenario.getIgnoreStepFailures();
+                        if (ignoreStepFailures == true && !failureResults.isEmpty()) {
                             stepOutcomeGreen = notificationHandler.handleAssertion(
                                     notifier,
                                     description,
@@ -395,11 +406,11 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
 
     private String getFullyQualifiedRestUrl(String serviceEndPoint) {
 
-        if(host == null || port == null){
+        if (host == null || port == null) {
             throw new RuntimeException("'" + PROPERTY_KEY_HOST + "' or 'port' - can not be null");
         }
 
-        if(applicationContext == null){
+        if (applicationContext == null) {
             throw new RuntimeException("'" + PROPERTY_KEY_PORT + "' key must be present even if empty or blank");
         }
 
@@ -433,4 +444,16 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
 
     }
 
+    private Step createFromStepFile(Step thisStep, String stepId) {
+        if (thisStep.getStepFile() != null) {
+            try {
+                thisStep = objectMapper.treeToValue(thisStep.getStepFile(), Step.class);
+            } catch (JsonProcessingException e) {
+                LOGGER.error("\n### Error while parsing for stepId - {}, stepFile - {}",
+                        stepId, thisStep.getStepFile());
+                throw new RuntimeException(e);
+            }
+        }
+        return thisStep;
+    }
 }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
index 5ec430df..2e44271c 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
@@ -207,7 +207,9 @@ public class ZeroCodeUnitRunner extends BlockJUnit4ClassRunner {
         if (passed) {
             LOGGER.info(String.format("\n**FINISHED executing all Steps for [%s] **.\nSteps were:%s",
                     child.getScenarioName(),
-                    child.getSteps().stream().map(step -> step.getName()).collect(Collectors.toList())));
+                    child.getSteps().stream()
+                            .map(step -> step.getName() == null ? step.getId() : step.getName())
+                            .collect(Collectors.toList())));
         }
 
         notifier.fireTestFinished(description);


Test patch:
diff --git a/core/src/test/java/org/jsmart/zerocode/core/domain/StepTest.java b/core/src/test/java/org/jsmart/zerocode/core/domain/StepTest.java
index 600f7e3f..4a8fd39d 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/domain/StepTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/domain/StepTest.java
@@ -25,7 +25,7 @@ import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 @RunWith(JukitoRunner.class)
-//@UseModules(ApplicationMainModule.class)
+// Or use - @UseModules(ApplicationMainModule.class)
 public class StepTest {
     public static class JukitoModule extends TestModule {
         @Override
@@ -43,16 +43,6 @@ public class StepTest {
     @Inject
     private ObjectMapper mapper;
 
-    @Before
-    public void beforeMethod() throws Exception {
-        /**
-         * This also tests your injection wirings.
-         * Running via JukitoRunner doesnt need this.
-         */
-        //mapper = new ObjectMapper();
-
-    }
-
     @Test
     public void shouldDeserializeSingleStep() throws Exception {
         String jsonDocumentAsString = smartUtils.getJsonDocumentAsString("01_test_smart_test_cases/01_test_json_single_step.json");
@@ -75,12 +65,20 @@ public class StepTest {
 
         assertThat(headerMap.get("Cookie"), is("cookie_123"));
         assertThat(queryParamsMap.get("invId"), is(10101));
-        //assertThat(stepDeserialized.getAssertions().getStatus(), is(201));
         assertThat(stepDeserialized.getAssertions().get("status").asInt(), is(201));
         assertThat(stepDeserialized.getAssertions().get("status").asLong(), is(201L));
         assertThat(stepDeserialized.getAssertions().get("status").asText(), is("201"));
     }
 
+    @Test
+    public void testDeserExternalStepFile() throws Exception {
+        String jsonDocumentAsString = smartUtils.getJsonDocumentAsString("01_test_smart_test_cases/05_test_external_step_reuse.json");
+        Step stepDeserialized = mapper.readValue(jsonDocumentAsString, Step.class);
+        assertThat(stepDeserialized, notNullValue());
+        assertThat(stepDeserialized.getId(), is("step1"));
+        assertThat(stepDeserialized.getStepFile().asText(), is("file/path"));
+    }
+
     @Test
     public void shouldSerializeSingleStep() throws Exception {
         String jsonDocumentAsString = smartUtils.getJsonDocumentAsString("01_test_smart_test_cases/01_test_json_single_step.json");
@@ -89,7 +87,6 @@ public class StepTest {
         JsonNode singleStepNode = mapper.valueToTree(stepDeserialized);
         String singleStepNodeString = mapper.writeValueAsString(singleStepNode);
 
-        // jayway json assert with this string.
         JSONAssert.assertEquals(singleStepNodeString, jsonDocumentAsString, true);
 
         assertThat(singleStepNode.get("name").asText(), is("StepNameWithoutSpaceEgCREATE"));
@@ -112,11 +109,4 @@ public class StepTest {
          */
     }
 
-    /**
-     * Do not use this private method as this has been moved to SmartUtils
-     **/
-    protected String getJsonDocumentAsString(String name) throws IOException {
-        String jsonAsString = Resources.toString(getClass().getClassLoader().getResource(name), StandardCharsets.UTF_8);
-        return jsonAsString;
-    }
 }
\ No newline at end of file
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 9c57ea73..dd14c06f 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
@@ -70,7 +70,7 @@ public class SmartUtilsTest {
     @Test
     public void willReadAllfileNamesFrom_TestResource() throws Exception {
         List<String> allTestCaseFiles = SmartUtils.getAllEndPointFiles("01_test_smart_test_cases");
-        assertThat(allTestCaseFiles.size(), is(5));
+        assertThat(allTestCaseFiles.size(), is(6));
         assertThat(allTestCaseFiles.get(0).toString(), is("01_test_smart_test_cases/01_test_json_single_step.json"));
     }
 
diff --git a/core/src/test/resources/01_test_smart_test_cases/05_test_external_step_reuse.json b/core/src/test/resources/01_test_smart_test_cases/05_test_external_step_reuse.json
new file mode 100755
index 00000000..8efcf105
--- /dev/null
+++ b/core/src/test/resources/01_test_smart_test_cases/05_test_external_step_reuse.json
@@ -0,0 +1,5 @@
+{
+  "id" : "step1",
+  "stepFile": "file/path"
+
+}
\ No newline at end of file
diff --git a/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldgithub/GitHubXStepReuseTest.java b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldgithub/GitHubXStepReuseTest.java
new file mode 100644
index 00000000..727413aa
--- /dev/null
+++ b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldgithub/GitHubXStepReuseTest.java
@@ -0,0 +1,22 @@
+package org.jsmart.zerocode.testhelp.tests.helloworldgithub;
+
+import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.domain.UseHttpClient;
+import org.jsmart.zerocode.core.httpclient.ssl.SslTrustHttpClient;
+import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@TargetEnv("github_host.properties")
+@UseHttpClient(SslTrustHttpClient.class)
+@RunWith(ZeroCodeUnitRunner.class)
+public class GitHubXStepReuseTest {
+
+    @Test
+    @JsonTestCase("helloworld_github_REST_api/GitHub_REST_api_step_reuse.json")
+    public void gitHubRestApi_externalStepReuse() throws Exception {
+
+    }
+
+}
diff --git a/http-testing/src/test/resources/helloworld_github_REST_api/GitHub_REST_api_more_assertions.json b/http-testing/src/test/resources/helloworld_github_REST_api/GitHub_REST_api_more_assertions.json
index 403d05ec..1fff147b 100644
--- a/http-testing/src/test/resources/helloworld_github_REST_api/GitHub_REST_api_more_assertions.json
+++ b/http-testing/src/test/resources/helloworld_github_REST_api/GitHub_REST_api_more_assertions.json
@@ -4,16 +4,14 @@
         {
             "name": "get_github_server_details",
             "url": "/users/albertosipov",
-            //"url": "https://api.github.com/users/octocat/orgs", // Also ok to type the full url here
             "operation": "GET",
             "request": {
             },
             "assertions": {
                 "status": 200,
                 "body": {
-                    "login" : "albertosipov",
-                    "id" : 36400587
-                    // and more fields, arrays assertions etc to go here.
+                    "login": "albertosipov",
+                    "id": 36400587
                 }
             }
         }
diff --git a/http-testing/src/test/resources/helloworld_github_REST_api/GitHub_REST_api_step_reuse.json b/http-testing/src/test/resources/helloworld_github_REST_api/GitHub_REST_api_step_reuse.json
new file mode 100644
index 00000000..3f2f632c
--- /dev/null
+++ b/http-testing/src/test/resources/helloworld_github_REST_api/GitHub_REST_api_step_reuse.json
@@ -0,0 +1,14 @@
+{
+    "scenarioName": "GitHub Step Reuse @@Alex",
+    "steps": [
+        {
+            "id" : "step1",
+            "stepFile": "${JSON.FILE:steps/step1.json}"
+
+        },
+        {
+            "id": "step2",
+            "stepFile": "${JSON.FILE:steps/step2.json}"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/http-testing/src/test/resources/steps/step1.json b/http-testing/src/test/resources/steps/step1.json
new file mode 100644
index 00000000..e38252f3
--- /dev/null
+++ b/http-testing/src/test/resources/steps/step1.json
@@ -0,0 +1,14 @@
+{
+    "name": "get_github_server_details_1",
+    "url": "/users/albertosipov",
+    "operation": "GET",
+    "request": {
+    },
+    "assertions": {
+        "status": 200,
+        "body": {
+            "login": "albertosipov",
+            "id": 36400587
+        }
+    }
+}
\ No newline at end of file
diff --git a/http-testing/src/test/resources/steps/step2.json b/http-testing/src/test/resources/steps/step2.json
new file mode 100644
index 00000000..ed322baf
--- /dev/null
+++ b/http-testing/src/test/resources/steps/step2.json
@@ -0,0 +1,14 @@
+{
+    "name": "get_github_server_details_2",
+    "url": "/users/albertosipov",
+    "operation": "GET",
+    "request": {
+    },
+    "assertions": {
+        "status": 200,
+        "body": {
+            "login": "albertosipov",
+            "id": 36400587
+        }
+    }
+}
\ No newline at end of file