Skip to content

Commit

Permalink
Merge branch 'master' into maven_dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
authorjapps authored Feb 16, 2024
2 parents 1633e74 + f72319d commit 3a31bbf
Show file tree
Hide file tree
Showing 56 changed files with 1,720 additions and 316 deletions.
8 changes: 8 additions & 0 deletions BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,17 @@ or
mvn -pl core clean test
```

## Runing Only The Integration tests(core)
Right click and run the "integrationtests" package. It picks the tests ending with "*Test.java"
<img width="632" alt="integration_tests_only_running_" src="https://github.com/authorjapps/zerocode/assets/12598420/6b6e8e33-16c1-43ce-8179-62a18e9a2290">


## With tests executed(kafka)
Some tests require a running Kafka (and some related components like kafka-rest, and kafka-schema-registry).

Location:
https://github.com/authorjapps/zerocode/blob/master/docker/compose/kafka-schema-registry.yml

Download the file, and run(or `cd to the docker/compose` dir and run)
```
docker-compose -f kafka-schema-registry.yml up -d
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Documentation
===
For a quick introduction to Zerocode and its features, visit the
+ [Zerocode TDD Doc Site](https://zerocode-tdd-docs.pages.dev)
+ [Wan to contribute or Improve](https://github.com/authorjapps/zerocode/wiki/Documentation-How-To-Fix-Steps)? Steps and guidelines are [here](https://github.com/authorjapps/zerocode/wiki/Documentation-How-To-Fix-Steps)

IDE Support By
===
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public interface ZeroCodeReportConstants {
String REPORT_TITLE_DEFAULT = "Zerocode Test Report";
String REPORT_DISPLAY_NAME_DEFAULT = "Zerocode Interactive Report";
String DEFAULT_REGRESSION_CATEGORY = "Regression";
String DEFAULT_REGRESSION_AUTHOR = "All";
String LINK_LABEL_NAME = "Spike Chart(Click here)";
String ZEROCODE_JUNIT = "zerocode.junit";
String CHARTS_AND_CSV = "gen-smart-charts-csv-reports";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
package org.jsmart.zerocode.core.domain;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Parameterized {
private final List<Object> valueSource;
private final List<String> csvSource;
private final Boolean ignoreHeader;

public Parameterized(
@JsonProperty("valueSource") List<Object> valueSource,
@JsonProperty("csvSource") List<String> csvSource) {
@JsonProperty("csvSource") JsonNode csvSourceJsonNode,
@JsonProperty("ignoreHeader") Boolean ignoreHeader) {
this.valueSource = valueSource;
this.csvSource = csvSource;
this.ignoreHeader = Optional.ofNullable(ignoreHeader).orElse(false);
this.csvSource = getCsvSourceFrom(csvSourceJsonNode);
}

public List<Object> getValueSource() {
Expand All @@ -22,6 +38,43 @@ public List<String> getCsvSource() {
return csvSource;
}

private List<String> getCsvSourceFrom(JsonNode csvSourceJsonNode) {
try {
if (csvSourceJsonNode.isArray()) {
return readCsvSourceFromJson(csvSourceJsonNode);

} else {
return readCsvSourceFromExternalCsvFile(csvSourceJsonNode);
}
} catch (IOException e) {
throw new RuntimeException("Error deserializing csvSource", e);
}
}

private List<String> readCsvSourceFromJson(JsonNode csvSourceJsonNode) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.readerFor(new TypeReference<List<String>>() {
});
return reader.readValue(csvSourceJsonNode);
}

private List<String> readCsvSourceFromExternalCsvFile(JsonNode csvSourceJsonNode) throws IOException {
String csvSourceFilePath = csvSourceJsonNode.textValue();
if (StringUtils.isNotBlank(csvSourceFilePath)) {
Path path = Paths.get("./src/test/resources/",csvSourceFilePath);
List<String> csvSourceFileLines = Files.lines(path)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
if (this.ignoreHeader) {
return csvSourceFileLines.stream()
.skip(1)
.collect(Collectors.toList());
}
return csvSourceFileLines;
}
return Collections.emptyList();
}

@Override
public String toString() {
return "Parameterized{" +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jsmart.zerocode.core.engine.preprocessor;

import org.jsmart.zerocode.core.domain.Step;
import org.jsmart.zerocode.core.engine.assertion.FieldAssertionMatcher;
import org.jsmart.zerocode.core.engine.assertion.JsonAsserter;

Expand All @@ -18,4 +19,11 @@ public interface ZeroCodeAssertionsProcessor {
List<JsonAsserter> createJsonAsserters(String resolvedAssertionJson);

List<FieldAssertionMatcher> assertAllAndReturnFailed(List<JsonAsserter> asserters, String executionResult);

Step resolveJsonContent(Step thisStep, ScenarioExecutionState scenarioExecutionState);

String fieldMasksRemoved(String resolvedRequestJson);

String fieldMasksApplied(String resolvedRequestJson);

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
package org.jsmart.zerocode.core.engine.preprocessor;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;
import org.apache.commons.lang.text.StrSubstitutor;
import org.jsmart.zerocode.core.domain.Step;
import org.jsmart.zerocode.core.engine.assertion.FieldAssertionMatcher;
import org.jsmart.zerocode.core.engine.assertion.JsonAsserter;
import org.jsmart.zerocode.core.engine.assertion.array.ArrayIsEmptyAsserterImpl;
import org.jsmart.zerocode.core.engine.assertion.array.ArraySizeAsserterImpl;
import org.jsmart.zerocode.core.engine.assertion.field.FieldContainsStringAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldContainsStringIgnoreCaseAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldHasDateAfterValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldHasDateBeforeValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldHasEqualNumberValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldHasExactValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldHasGreaterThanValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldHasInEqualNumberValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldHasLesserThanValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldIsNotNullAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldIsNullAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldIsOneOfValueAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldMatchesCustomAsserter;
import org.jsmart.zerocode.core.engine.assertion.field.FieldMatchesRegexPatternAsserter;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
Expand All @@ -18,28 +41,47 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
import net.minidev.json.JSONArray;
import org.apache.commons.lang.text.StrSubstitutor;
import org.jsmart.zerocode.core.engine.assertion.FieldAssertionMatcher;
import org.jsmart.zerocode.core.engine.assertion.JsonAsserter;
import org.jsmart.zerocode.core.engine.assertion.array.ArrayIsEmptyAsserterImpl;
import org.jsmart.zerocode.core.engine.assertion.array.ArraySizeAsserterImpl;
import org.jsmart.zerocode.core.engine.assertion.field.*;

import static java.lang.Integer.valueOf;
import static java.lang.String.format;
import static org.apache.commons.lang.StringEscapeUtils.escapeJava;
import static org.apache.commons.lang.StringUtils.substringBetween;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.*;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_LOCAL_DATETIME_AFTER;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_LOCAL_DATETIME_BEFORE;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_PATH_SIZE;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_CONTAINS_STRING;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_CONTAINS_STRING_IGNORE_CASE;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_CUSTOM_ASSERT;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_EMPTY_ARRAY;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_EQUAL_TO_NUMBER;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_GREATER_THAN;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_IS_NOT_NULL;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_IS_NULL;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_IS_ONE_OF;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_LESSER_THAN;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_MATCHES_STRING;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_NOT_EQUAL_TO_NUMBER;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_NOT_NULL;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_NULL;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_ONE_OF;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.RAW_BODY;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeValueTokens.$VALUE;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeValueTokens.JSON_CONTENT;
import static org.jsmart.zerocode.core.utils.FieldTypeConversionUtils.deepTypeCast;
import static org.jsmart.zerocode.core.utils.FieldTypeConversionUtils.fieldTypes;
import static org.jsmart.zerocode.core.utils.PropertiesProviderUtils.loadAbsoluteProperties;
import static org.jsmart.zerocode.core.utils.SmartUtils.checkDigNeeded;
import static org.jsmart.zerocode.core.utils.SmartUtils.getJsonFilePhToken;
import static org.jsmart.zerocode.core.utils.SmartUtils.isValidAbsolutePath;
import static org.jsmart.zerocode.core.utils.TokenUtils.getMasksRemoved;
import static org.jsmart.zerocode.core.utils.TokenUtils.getMasksReplaced;
import static org.jsmart.zerocode.core.utils.TokenUtils.getTestCaseTokens;
import static org.jsmart.zerocode.core.utils.TokenUtils.populateParamMap;
import static org.slf4j.LoggerFactory.getLogger;

;
;

public class ZeroCodeAssertionsProcessorImpl implements ZeroCodeAssertionsProcessor {

private static final org.slf4j.Logger LOGGER = getLogger(ZeroCodeAssertionsProcessorImpl.class);
Expand Down Expand Up @@ -337,6 +379,49 @@ public List<FieldAssertionMatcher> assertAllAndReturnFailed(List<JsonAsserter> a
return failedReports;
}

/**
* Resolves JSON.CONTENT as object or array
*
* First the logic checks if dig-deep needed to avoid unwanted recursions. If not needed, the step definition is
* returned intact. Otherwise calls the dig deep method to perform the operation.
*
* @param thisStep
* @return The effective step definition
*/
@Override
public Step resolveJsonContent(Step thisStep, ScenarioExecutionState scenarioExecutionState) {
try {
if (!checkDigNeeded(mapper, thisStep, JSON_CONTENT)) {
return thisStep;
}

JsonNode stepNode = mapper.convertValue(thisStep, JsonNode.class);

Map<String, Object> stepMap = mapper.readValue(stepNode.toString(), new TypeReference<Map<String, Object>>() {
});

digReplaceContent(stepMap, scenarioExecutionState);

JsonNode jsonStepNode = mapper.valueToTree(stepMap);

return mapper.treeToValue(jsonStepNode, Step.class);

} catch (Exception e) {
LOGGER.error("Json content reading exception - {}", e.getMessage());
throw new RuntimeException("Json content reading exception. Details - " + e);
}
}

@Override
public String fieldMasksRemoved(String resolvedRequestJson) {
return getMasksRemoved(resolvedRequestJson);
}

@Override
public String fieldMasksApplied(String resolvedRequestJson) {
return getMasksReplaced(resolvedRequestJson);
}

private void loadAnnotatedHostProperties() {
try {
if(isValidAbsolutePath(hostFileName)){
Expand Down Expand Up @@ -408,4 +493,39 @@ private boolean hasNoTypeCast(String resolvedJson) {
}


void digReplaceContent(Map<String, Object> map, ScenarioExecutionState scenarioExecutionState) {
map.entrySet().forEach(entry -> {
Object value = entry.getValue();

if (value instanceof Map) {
digReplaceContent((Map<String, Object>) value, scenarioExecutionState);
} else {
LOGGER.debug("Leaf node found = {}, checking for any json content...", value);
if (value != null && (value.toString().contains(JSON_CONTENT))) {
LOGGER.debug("Found JSON content place holder = {}. Replacing with content", value);
String valueString = value.toString();
String token = getJsonFilePhToken(valueString);

if (token != null && (token.startsWith(JSON_CONTENT))) {
try {
String resolvedRequestJson = resolveStringJson(
"${" + token.substring(JSON_CONTENT.length()) + "}",
scenarioExecutionState.getResolvedScenarioState());
resolvedRequestJson = resolvedRequestJson.replaceAll("\\\\", "");
try {
JsonNode jsonNode = mapper.readTree(resolvedRequestJson);
entry.setValue(jsonNode);
} catch (JsonParseException e) {
//value is not a json string, but a string value
entry.setValue(resolvedRequestJson);
}
} catch (Exception exx) {
LOGGER.error("External file reference exception - {}", exx.getMessage());
throw new RuntimeException(exx);
}
}
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@

import com.google.inject.name.Named;
import org.jsmart.zerocode.core.domain.Step;
import org.jsmart.zerocode.core.utils.SmartUtils;
import org.slf4j.Logger;

import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeValueTokens.JSON_PAYLOAD_FILE;
import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeValueTokens.YAML_PAYLOAD_FILE;
import static org.jsmart.zerocode.core.utils.SmartUtils.readJsonAsString;
import static org.jsmart.zerocode.core.utils.SmartUtils.readYamlAsString;
import static org.jsmart.zerocode.core.utils.SmartUtils.checkDigNeeded;
import static org.jsmart.zerocode.core.utils.SmartUtils.getJsonFilePhToken;
import static org.jsmart.zerocode.core.utils.TokenUtils.getTestCaseTokens;
import static org.slf4j.LoggerFactory.getLogger;

Expand Down Expand Up @@ -69,7 +72,7 @@ public Step resolveExtJsonFile(Step thisStep) {

try {

if (!checkDigNeeded(thisStep)) {
if (!checkDigNeeded(objectMapper, thisStep, JSON_PAYLOAD_FILE, YAML_PAYLOAD_FILE)) {
return thisStep;
}

Expand Down Expand Up @@ -176,22 +179,4 @@ else if (token != null && token.startsWith(OTHER_FILE)) {
}
});
}

private String getJsonFilePhToken(String valueString) {
if (valueString != null) {
List<String> allTokens = getTestCaseTokens(valueString);
if (allTokens != null && !allTokens.isEmpty()) {
return allTokens.get(0);
}
}
return null;
}

boolean checkDigNeeded(Step thisStep) throws JsonProcessingException {
String stepJson = objectMapper.writeValueAsString(thisStep);
List<String> allTokens = getTestCaseTokens(stepJson);

return allTokens.toString().contains(JSON_PAYLOAD_FILE) || allTokens.toString().contains(YAML_PAYLOAD_FILE);
}

}
Loading

0 comments on commit 3a31bbf

Please sign in to comment.