Skip to content

Commit

Permalink
[JENKINS-43055] Backporting #51 into 2.11.x.
Browse files Browse the repository at this point in the history
  • Loading branch information
jglick committed Jun 20, 2017
2 parents eaee337 + 813ca3a commit 3b5621d
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 1 deletion.
7 changes: 6 additions & 1 deletion pom.xml
Expand Up @@ -73,7 +73,12 @@
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>2.9</version>
<version>2.10</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.15</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
Expand Down
Expand Up @@ -103,6 +103,7 @@
import org.jenkinsci.plugins.workflow.flow.FlowDefinition;
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionList;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionListener;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
import org.jenkinsci.plugins.workflow.flow.GraphListener;
import org.jenkinsci.plugins.workflow.flow.StashManager;
Expand Down Expand Up @@ -239,6 +240,8 @@ public WorkflowRun(WorkflowJob job, File dir) throws IOException {
execution = newExecution;
newExecution.start();
executionPromise.set(newExecution);
FlowExecutionListener.fireRunning(execution);

} catch (Throwable x) {
execution = null; // ensures isInProgress returns false
finish(Result.FAILURE, x);
Expand Down Expand Up @@ -590,6 +593,8 @@ private String key() {
executionPromise.set(execution);
if (!execution.isComplete()) {
// we've been restarted while we were running. let's get the execution going again.
FlowExecutionListener.fireResumed(execution);

try {
OutputStream logger = new FileOutputStream(getLogFile(), true);
listener = new StreamBuildListener(logger, Charset.defaultCharset());
Expand Down Expand Up @@ -659,6 +664,10 @@ private void finish(@Nonnull Result r, @CheckForNull Throwable t) {
} catch (IOException x) {
LOGGER.log(Level.WARNING, "failed to clean up stashes from " + this, x);
}
FlowExecution exec = getExecution();
if (exec != null) {
FlowExecutionListener.fireCompleted(exec);
}
}

@Override public void deleteArtifacts() throws IOException {
Expand Down
Expand Up @@ -25,10 +25,17 @@
package org.jenkinsci.plugins.workflow.job;

import com.google.inject.Inject;
import hudson.ExtensionList;
import hudson.model.Executor;
import hudson.model.Result;
import hudson.model.TaskListener;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionList;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionListener;
import org.jenkinsci.plugins.workflow.flow.GraphListener;
import org.jenkinsci.plugins.workflow.graph.FlowEndNode;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
Expand All @@ -46,6 +53,8 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import java.util.List;

public class WorkflowRunRestartTest {

@ClassRule public static BuildWatcher buildWatcher = new BuildWatcher();
Expand Down Expand Up @@ -175,4 +184,116 @@ public DescriptorImpl() {
}
}

@Issue("JENKINS-43055")
@Test
public void flowExecutionListener() throws Exception {
story.addStep(new Statement() {
@Override
public void evaluate() throws Throwable {
WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("echo 'Running for listener'\n" +
"sleep 0\n" +
"semaphore 'wait'\n" +
"sleep 0\n" +
"semaphore 'post-resume'\n" +
"sleep 0\n" +
"error 'fail'\n", true));
WorkflowRun b = p.scheduleBuild2(0).waitForStart();
SemaphoreStep.waitForStart("wait/1", b);
ExecListener listener = ExtensionList.lookup(FlowExecutionListener.class).get(ExecListener.class);
assertNotNull(listener);
assertEquals(1, listener.started);
assertEquals(0, listener.resumed);
assertEquals(0, listener.finished);
}
});
story.addStep(new Statement() {
@Override
public void evaluate() throws Throwable {
WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class);
WorkflowRun b = p.getLastBuild();
assertTrue(b.isBuilding());
SemaphoreStep.success("wait/1", null);

SemaphoreStep.waitForStart("post-resume/1", b);
ExecListener listener = ExtensionList.lookup(FlowExecutionListener.class).get(ExecListener.class);
assertNotNull(listener);
assertEquals(0, listener.started);
assertEquals(1, listener.resumed);
assertEquals(0, listener.finished);

SemaphoreStep.success("post-resume/1", null);

story.j.assertBuildStatus(Result.FAILURE, story.j.waitForCompletion(b));
story.j.assertLogContains("Running for listener", b);

assertEquals(0, listener.started);
assertEquals(1, listener.resumed);
assertEquals(1, listener.finished);
assertTrue(listener.graphListener.wasCalledBeforeExecListener);
}
});

}

@TestExtension("flowExecutionListener")
public static class ExecListener extends FlowExecutionListener {
int started;
int finished;
int resumed;
ExecGraphListener graphListener = new ExecGraphListener();

@Override
public void onRunning(FlowExecution execution) {
addGraphListenerCheckList(execution);
started++;
}

@Override
public void onResumed(FlowExecution execution) {
addGraphListenerCheckList(execution);
resumed++;
}

private void addGraphListenerCheckList(FlowExecution execution) {
execution.addListener(graphListener);
boolean listHasExec = false;
for (FlowExecution e : FlowExecutionList.get()) {
if (e.equals(execution)) {
listHasExec = true;
}
}
assertTrue(listHasExec);
}

@Override
public void onCompleted(FlowExecution execution) {
finished++;
for (FlowExecution e : FlowExecutionList.get()) {
assertNotEquals(e, execution);
}

assertTrue(execution.isComplete());
assertNotNull(execution.getCauseOfFailure());
List<FlowNode> heads = execution.getCurrentHeads();
assertEquals(1, heads.size());
assertTrue(heads.get(0) instanceof FlowEndNode);
FlowEndNode node = (FlowEndNode)heads.get(0);
assertEquals(Result.FAILURE, node.getResult());
}
}

public static class ExecGraphListener implements GraphListener.Synchronous {
boolean wasCalledBeforeExecListener;

@Override
public void onNewHead(FlowNode node) {
if (node instanceof FlowEndNode) {
ExecListener listener = ExtensionList.lookup(FlowExecutionListener.class).get(ExecListener.class);
if (listener.finished == 0) {
wasCalledBeforeExecListener = true;
}
}
}
}
}

0 comments on commit 3b5621d

Please sign in to comment.