Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add timeout to iterating action containers #1261

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@
import org.citrusframework.container.AbstractIteratingActionContainer;
import org.citrusframework.container.IteratingConditionExpression;

import java.time.Duration;

public abstract class AbstractIteratingContainerBuilder<T extends AbstractIteratingActionContainer, S extends AbstractIteratingContainerBuilder<T, S>> extends AbstractTestContainerBuilder<T, S> {

protected String condition;
protected IteratingConditionExpression conditionExpression;
protected String indexName = "i";
protected Duration timeout;
protected int index;
protected int start = 1;

/**
* Adds a condition to this iterate container.
* @param condition
* @return
*/
public S condition(String condition) {
this.condition = condition;
Expand All @@ -39,8 +40,6 @@ public S condition(String condition) {

/**
* Adds a condition expression to this iterate container.
* @param condition
* @return
*/
public S condition(IteratingConditionExpression condition) {
this.conditionExpression = condition;
Expand All @@ -49,70 +48,73 @@ public S condition(IteratingConditionExpression condition) {

/**
* Sets the index variable name.
* @param name
* @return
*/
public S index(String name) {
this.indexName = name;
return self;
}

public S timeout(Duration timeout) {
this.timeout = timeout;
return self;
}

/**
* Sets the index start value.
* @param index
* @return
*/
public S startsWith(int index) {
this.start = index;
return self;
}

@Override
public T build() {
if (condition == null && conditionExpression == null) {
conditionExpression = (index, context) -> index > 10;
}

return super.build();
}

/**
* Gets the condition.
* @return the condition
*/
public String getCondition() {
return condition;
}

/**
* Gets the condition.
* @return the conditionExpression
* @return the condition expression
*/
public IteratingConditionExpression getConditionExpression() {
return conditionExpression;
}

/**
* Gets the indexName.
* @return the indexName
* @return the index name
*/
public String getIndexName() {
return indexName;
}

/**
* Gets the index.
* @return the timeout duration
*/
public Duration getTimeout() {
return timeout;
}

/**
* @return the index
*/
public int getIndex() {
return index;
}

/**
* Gets the start index.
* @return
* @return the start index
*/
public int getStart() {
return start;
}

@Override
public T build() {
if (condition == null && conditionExpression == null) {
conditionExpression = (index, context) -> index > 10;
}

return super.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,63 +20,161 @@
import org.citrusframework.TestActionBuilder;
import org.citrusframework.context.TestContext;
import org.citrusframework.context.TestContextFactory;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.citrusframework.exceptions.ValidationException;
import org.citrusframework.util.BooleanExpressionParser;
import org.citrusframework.validation.matcher.ValidationMatcherUtils;

import java.time.Duration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import static java.lang.Thread.currentThread;
import static java.util.Objects.nonNull;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

public abstract class AbstractIteratingActionContainer extends AbstractActionContainer {
/** Boolean expression string */

/**
* Boolean expression string
*/
protected final String condition;

/** Optional condition expression evaluates to true or false */
/**
* Optional condition expression evaluates to true or false
*/
protected final IteratingConditionExpression conditionExpression;

/** Name of index variable */
/**
* Looping index
*/
protected int index;

/**
* Name of index variable
*/
protected final String indexName;

/** Cache start index for further container executions - e.g. in loop */
/**
* Cache start index for further container executions - e.g. in loop
*/
protected final int start;

/** Looping index */
protected int index;
/**
* The maximum duration this iteration can take until it reaches a timeout.
*/
private final Duration timeout;

public AbstractIteratingActionContainer(String name, AbstractIteratingContainerBuilder<?, ?> builder) {
super(name, builder);

this.condition = builder.getCondition();
this.conditionExpression = builder.getConditionExpression();
this.indexName = builder.getIndexName();
this.index = builder.getIndex();
this.indexName = builder.getIndexName();
this.start = builder.getStart();
this.timeout = builder.getTimeout();
}

@Override
public final void doExecute(TestContext context) {
index = start;
executeIteration(context);

if (nonNull(timeout) && timeout.toMillis() > 0) {
executeIterationWithTimeout(context);
} else {
executeIteration(context);
}
}

private void executeIterationWithTimeout(TestContext context) {
var executor = newSingleThreadExecutor();

try {
var future = executor.submit(() -> executeIteration(context));
future.get(timeout.toMillis(), MILLISECONDS);
} catch (ExecutionException | TimeoutException e) {
throw new CitrusRuntimeException("Iteration reached timeout!", e);
} catch (InterruptedException e) {
currentThread().interrupt();
throw new RuntimeException(e);
} finally {
executor.shutdown();
}
}

@Override
public boolean isDone(TestContext context) {
return super.isDone(context) || !checkCondition(context);
}

/**
* @return the condition
*/
public String getCondition() {
return condition;
}

/**
* @return the condition expression
*/
public IteratingConditionExpression getConditionExpression() {
return conditionExpression;
}

/**
* @return the index
*/
public int getIndex() {
return index;
}

/**
* @return the index name
*/
public String getIndexName() {
return indexName;
}

/**
* @return the start index
*/
public int getStart() {
return start;
}

/**
* The maximum duration this iteration can take until it reaches a timeout.
*/
public Duration getTimeout() {
return timeout;
}

/**
* Execute embedded actions in loop.
* @param context TestContext holding variable information.
*
* @param context Test context holding variable information.
*/
protected abstract void executeIteration(TestContext context);

/**
* Executes the nested test actions.
* @param context
*
* @param context Test context holding variable information.
*/
protected void executeActions(TestContext context) {
context.setVariable(indexName, String.valueOf(index));

for (TestActionBuilder<?> actionBuilder: actions) {
for (TestActionBuilder<?> actionBuilder : actions) {
executeAction(actionBuilder.build(), context);
}
}

/**
* Check aborting condition.
* @return
*
* @return whether the conditioning has been satisfied.
*/
protected boolean checkCondition(TestContext context) {
if (conditionExpression != null) {
Expand Down Expand Up @@ -104,49 +202,4 @@ protected boolean checkCondition(TestContext context) {

return BooleanExpressionParser.evaluate(conditionString);
}

@Override
public boolean isDone(TestContext context) {
return super.isDone(context) || !checkCondition(context);
}

/**
* Gets the condition.
* @return the condition
*/
public String getCondition() {
return condition;
}

/**
* Gets the condition.
* @return the conditionExpression
*/
public IteratingConditionExpression getConditionExpression() {
return conditionExpression;
}

/**
* Gets the indexName.
* @return the indexName
*/
public String getIndexName() {
return indexName;
}

/**
* Gets the index.
* @return the index
*/
public int getIndex() {
return index;
}

/**
* Gets the start index.
* @return
*/
public int getStart() {
return start;
}
}
Loading
Loading