Skip to content

Commit

Permalink
feat(engine): Add SpEL support to RetryWithTimeOutStrategy (#203)
Browse files Browse the repository at this point in the history
Co-authored-by: red1 <redouaneelalami@gmail.com>
  • Loading branch information
Redouane-E and red1 authored Oct 21, 2024
1 parent 2d0fffb commit 6a1461d
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,12 @@ public Object evaluate(final Object o, final Map<String, Object> contextVariable
return evaluate(o, contextVariables, false);
}

public String evaluateString(final String s, final Map<String, Object> contextVariables) throws EvaluationException {
return (String) this.evaluate(s, contextVariables);
}

public String silentEvaluateString(final String s, final Map<String, Object> contextVariables) throws EvaluationException {
return (String) this.evaluate((Object) s, contextVariables, true);
return (String) this.evaluate(s, contextVariables, true);
}

public Target evaluateTarget(final Target target, final Map<String, Object> contextVariables) throws EvaluationException {
Expand Down Expand Up @@ -103,16 +107,16 @@ private Object evaluateObject(final Object object, final EvaluationContext evalu
Object inputEvaluatedValue;
if (object instanceof String stringValue) {
if (hasOnlyOneSpel(stringValue)) {
inputEvaluatedValue = Strings.replaceExpression(stringValue, s -> evaluate(parser, evaluationContext, s), EVALUATION_STRING_PREFIX, EVALUATION_STRING_SUFFIX, EVALUATION_STRING_ESCAPE, silentResolve);
inputEvaluatedValue = Strings.replaceExpression(stringValue, s -> evaluate(parser, evaluationContext, s), EVALUATION_STRING_PREFIX, EVALUATION_STRING_SUFFIX, EVALUATION_STRING_ESCAPE, silentResolve);
} else {
inputEvaluatedValue = Strings.replaceExpressions(stringValue, s -> evaluate(parser, evaluationContext, s), EVALUATION_STRING_PREFIX, EVALUATION_STRING_SUFFIX, EVALUATION_STRING_ESCAPE, silentResolve);
inputEvaluatedValue = Strings.replaceExpressions(stringValue, s -> evaluate(parser, evaluationContext, s), EVALUATION_STRING_PREFIX, EVALUATION_STRING_SUFFIX, EVALUATION_STRING_ESCAPE, silentResolve);
}
} else if (object instanceof Map map) {
Map evaluatedMap = new LinkedHashMap();
map.forEach(
(key, value) -> {
Object keyValue = evaluateObject(key, evaluationContext, silentResolve);
Object valueValue = evaluateObject(value, evaluationContext, silentResolve);
Object keyValue = evaluateObject(key, evaluationContext, silentResolve);
Object valueValue = evaluateObject(value, evaluationContext, silentResolve);
evaluatedMap.put(keyValue, valueValue);
if (keyValue instanceof String stringKeyValue) {
evaluationContext.setVariable(stringKeyValue, valueValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.chutneytesting.action.spi.time.Duration;
import com.chutneytesting.engine.domain.execution.ScenarioExecution;
import com.chutneytesting.engine.domain.execution.engine.scenario.ScenarioContext;
import com.chutneytesting.engine.domain.execution.engine.scenario.ScenarioContextImpl;
import com.chutneytesting.engine.domain.execution.engine.step.Step;
import com.chutneytesting.engine.domain.execution.report.Status;
import java.util.ArrayList;
Expand Down Expand Up @@ -61,21 +62,26 @@ public Status execute(ScenarioExecution scenarioExecution,
String timeOut = strategyDefinition.strategyProperties.getProperty("timeOut", String.class);
String retryDelay = strategyDefinition.strategyProperties.getProperty("retryDelay", String.class); // TODO - respect State of the art : provide number of retries policy instead
if (timeOut == null) {
throw new IllegalStateException("Undefined parameter 'timeOut'"); // TODO - be friendly -> provide a default value instead
throw new IllegalStateException("Undefined parameter 'timeOut'"); // TODO - Provide a default value instead
}
if (retryDelay == null) {
throw new IllegalStateException("Undefined parameter 'retryDelay'"); // TODO - be friendly -> provide a default value instead
throw new IllegalStateException("Undefined parameter 'retryDelay'"); // TODO - Provide a default value instead
}

Long timeOutMs = toMilliSeconds(timeOut);
Long retryDelayMs = toMilliSeconds(retryDelay);
Long timeLeft = timeOutMs;
Status st = Status.NOT_EXECUTED;
ScenarioContextImpl mergedContext = new ScenarioContextImpl();
mergedContext.putAll(scenarioContext);
mergedContext.putAll(localContext);

String evaluatedRetryDelay = step.dataEvaluator().evaluateString(retryDelay, mergedContext);
String evaluatedTimeOut = step.dataEvaluator().evaluateString(timeOut, mergedContext);
long retryDelayMs = toMilliSeconds(evaluatedRetryDelay);
long timeLeft = toMilliSeconds(evaluatedTimeOut);
Status st;
int tries = 1;
List<String> lastErrors = new ArrayList<>();
do {
Long tryStartTime = System.currentTimeMillis();
step.addInformation("Retry strategy definition : [timeOut " + timeOut + "] [delay " + retryDelay + "]");
long tryStartTime = System.currentTimeMillis();
step.addInformation("Retry strategy definition : [timeOut " + evaluatedTimeOut + "] [delay " + evaluatedRetryDelay + "]");
step.addInformation("Try number : " + (tries++));

st = executeAll(scenarioExecution, step, scenarioContext, localContext, strategies);
Expand All @@ -90,7 +96,7 @@ public Status execute(ScenarioExecution scenarioExecution,
}
timeLeft -= System.currentTimeMillis() - tryStartTime;
} else {
if(!lastErrors.isEmpty()){
if (!lastErrors.isEmpty()) {
step.addErrorMessage("Error(s) on last step execution:");
lastErrors.forEach(step::addErrorMessage);
}
Expand All @@ -106,6 +112,11 @@ public Status execute(ScenarioExecution scenarioExecution,
return st;
}

private long toMilliSeconds(String duration) {
double durationInMS = Duration.parse(duration).toMilliseconds();
return Math.round(durationInMS);
}

private Status executeAll(ScenarioExecution scenarioExecution,
Step step,
ScenarioContext scenarioContext,
Expand All @@ -121,13 +132,6 @@ private Status executeAll(ScenarioExecution scenarioExecution,
}
return Status.SUCCESS;
}

// convert duration strings in strategy parameters to milliseconds
private long toMilliSeconds(String duration) {
double durationInMS = Duration.parse(duration).toMilliseconds();
return Math.round(durationInMS);

}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void testInputDataEvaluator() {
assertThat(evaluatedInputs.get("objectAttributeValue")).isEqualTo("attributeValue");

assertThat(evaluatedInputs.get("map")).isInstanceOf(Map.class);
Map evaluatedMap = (Map<String, Object>)evaluatedInputs.get("map");
Map<String, Object> evaluatedMap = (Map<String, Object>) evaluatedInputs.get("map");
assertThat(evaluatedMap.get("stringRawValue")).isEqualTo("rawValue");
assertThat(evaluatedMap.get("objectRawValue")).isEqualTo(testObject);
assertThat(evaluatedMap.get("destination")).isEqualTo("stringDestination");
Expand All @@ -111,13 +111,13 @@ public void testInputDataEvaluator() {
assertThat(evaluatedMap.get("objectAttributeValue")).isEqualTo("attributeValue");

assertThat(evaluatedMap.get("innerMap")).isInstanceOf(Map.class);
Map evaluatedInnerMap = (Map<Object, Object>)evaluatedMap.get("innerMap");
Map<Object, Object> evaluatedInnerMap = (Map<Object, Object>) evaluatedMap.get("innerMap");
assertThat(evaluatedInnerMap.get("dateTimeFormat")).isEqualTo("ss");
assertThat(evaluatedInnerMap.get("dateTimeFormatRef")).isEqualTo("ss");


assertThat(evaluatedInputs.get("list")).isInstanceOf(List.class);
List evaluatedList = (List<Object>)evaluatedInputs.get("list");
List<Object> evaluatedList = (List<Object>) evaluatedInputs.get("list");
assertThat(evaluatedList.get(0)).isEqualTo("rawValue");
assertThat(evaluatedList.get(1)).isEqualTo(testObject);
assertThat(evaluatedList.get(2)).isEqualTo("stringDestination");
Expand All @@ -127,7 +127,7 @@ public void testInputDataEvaluator() {
assertThat(evaluatedList.get(6)).isEqualTo("attributeValue");

assertThat(evaluatedInputs.get("set")).isInstanceOf(Set.class);
Set evaluatedSet = (Set<Object>)evaluatedInputs.get("set");
Set<Object> evaluatedSet = (Set<Object>) evaluatedInputs.get("set");
assertThat(evaluatedSet).contains("rawValue");
assertThat(evaluatedSet).contains(testObject);
assertThat(evaluatedSet).contains("stringDestination");
Expand Down Expand Up @@ -210,6 +210,19 @@ public void should_resolve_known_vars_and_not_resolve_unknown_vars() {
assertThat(result).isEqualTo("test titi ${#tata}");
}

@Test
public void should_resolve_expression_as_string() {
// Given
Map<String, Object> context = new HashMap<>();
context.put("toto", "titi");

// When
String result = sut.evaluateString("test ${#toto}", context);

// Then
assertThat(result).isEqualTo("test titi");
}

@Test
public void should_evaluate_multiple_spel() {
// Given
Expand Down Expand Up @@ -247,18 +260,20 @@ public void should_evaluate_multiple_spel() {
assertThat(evaluatedInputs.get("twoVariablesWithTextAtBeginning")).isEqualTo("Text - toto - tata");
assertThat(evaluatedInputs.get("twoVariablesWithTextAtTheEnd")).isEqualTo("toto - tata - text");

assertThat(((Map)evaluatedInputs.get("object")).get("k1")).isEqualTo("value1");
assertThat(((Map)evaluatedInputs.get("objectWithSpaceAfter")).get("k2")).isEqualTo("value2");
assertThat(((Map)evaluatedInputs.get("objectWithSpaceBefore")).get("k3")).isEqualTo("value3");
assertThat(((Map)evaluatedInputs.get("objectWithSpaceAfterSuffix")).get("k4")).isEqualTo("value4");
assertThat(((Map)evaluatedInputs.get("objectWithSpaceBeforePrefix")).get("k5")).isEqualTo("value5");
assertThat(((Map) evaluatedInputs.get("object")).get("k1")).isEqualTo("value1");
assertThat(((Map) evaluatedInputs.get("objectWithSpaceAfter")).get("k2")).isEqualTo("value2");
assertThat(((Map) evaluatedInputs.get("objectWithSpaceBefore")).get("k3")).isEqualTo("value3");
assertThat(((Map) evaluatedInputs.get("objectWithSpaceAfterSuffix")).get("k4")).isEqualTo("value4");
assertThat(((Map) evaluatedInputs.get("objectWithSpaceBeforePrefix")).get("k5")).isEqualTo("value5");
}

private class TestObject {
private String attribute;
private static class TestObject {
private final String attribute;

public TestObject(String attribute) {
this.attribute = attribute;
}

public String attribute() {
return attribute;
}
Expand Down
Loading

0 comments on commit 6a1461d

Please sign in to comment.