package org.jenkinsci.plugins.workflow.steps.durable_task;
import com.google.common.base.Predicate;
import hudson.model.BallColor;
import hudson.model.Result;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.cps.CpsFlowExecution;
import org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable.Row;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import java.io.File;
import java.util.Arrays;
import java.util.concurrent.TimeoutException;
/**
* @author Kohsuke Kawaguchi
*/
public class ShellStepTest extends Assert {
@Rule
public JenkinsRule j = new JenkinsRule();
/**
* Failure in the shell script should mark the step as red
*/
@Test
public void failureShouldMarkNodeRed() throws Exception {
// job setup
WorkflowJob foo = j.jenkins.createProject(WorkflowJob.class, "foo");
foo.setDefinition(new CpsFlowDefinition(StringUtils.join(Arrays.asList(
"node {",
" sh 'false'",
"}"
), "\n")));
// get the build going, and wait until workflow pauses
WorkflowRun b = j.assertBuildStatus(Result.FAILURE, foo.scheduleBuild2(0).get());
boolean found = false;
FlowGraphTable t = new FlowGraphTable(b.getExecution());
t.build();
for (Row r : t.getRows()) {
if (r.getNode() instanceof StepAtomNode) {
StepAtomNode sa = (StepAtomNode) r.getNode();
if (sa.getDescriptor().getFunctionName().equals("sh")) {
assertSame(BallColor.RED, sa.getIconColor());
found = true;
}
}
}
assertTrue(found);
}
/**
* Abort a running workflow to ensure that the process is terminated.
*/
@Test
public void abort() throws Exception {
File tmp = File.createTempFile("jenkins","test");
tmp.delete();
// job setup
WorkflowJob foo = j.jenkins.createProject(WorkflowJob.class, "foo");
foo.setDefinition(new CpsFlowDefinition(StringUtils.join(Arrays.asList(
"node {",
" sh 'while true; do touch "+tmp+"; sleep 1; done'",
"}"
), "\n")));
// get the build going, and wait until workflow pauses
WorkflowRun b = foo.scheduleBuild2(0).getStartCondition().get();
CpsFlowExecution e = (CpsFlowExecution) b.getExecutionPromise().get();
e.waitForSuspension();
// at this point the file should be being touched
waitForCond(5000, tmp, new Predicate<File>() {
@Override
public boolean apply(File tmp) {
return tmp.exists();
}
});
e.interrupt(Result.ABORTED);
// touching should have stopped
final long refTimestamp = tmp.lastModified();
ensureForWhile(5000, tmp, new Predicate<File>() {
@Override
public boolean apply(File tmp) {
return refTimestamp==tmp.lastModified();
}
});
}
/**
* Waits up to the given timeout until the predicate is satisfied.
*/
private <T> void waitForCond(int timeout, T o, Predicate<T> predicate) throws Exception {
long goal = System.currentTimeMillis()+timeout;
while (System.currentTimeMillis()<goal) {
if (predicate.apply(o))
return;
Thread.sleep(100);
}
throw new TimeoutException();
}
/**
* Asserts that the predicate remains true up to the given timeout.
*/
private <T> void ensureForWhile(int timeout, T o, Predicate<T> predicate) throws Exception {
long goal = System.currentTimeMillis()+timeout;
while (System.currentTimeMillis()<goal) {
if (!predicate.apply(o))
throw new AssertionError(predicate);
Thread.sleep(100);
}
}
}