Skip to content

Commit

Permalink
[JENKINS-30102] Cancel the correct queued build
Browse files Browse the repository at this point in the history
Search in Jenkins.instance.queue for the queued object that
matches the future returned by scheduleBuild2.

Adding unittest for cancelling queued jobs.
  • Loading branch information
thomaste committed Sep 15, 2015
1 parent e835b49 commit 9711dc2
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/main/groovy/com/cloudbees/plugins/flow/JobInvocation.groovy
Expand Up @@ -110,7 +110,15 @@ public class JobInvocation {
/* package */ boolean abort() {
def aborted = false
if (!started) {
aborted = future.cancel(false)
// Need to search the queue for the correct job and cancel it in
// the queue.
def queue = Jenkins.instance.queue
for (queueItem in queue.items) {
if (future == queueItem.getFuture()) {
aborted = queue.cancel(queueItem)
break;
}
}
}
else if (!completed) {
// as the task has already started we want to be kinder in recording the cause.
Expand Down
62 changes: 62 additions & 0 deletions src/test/groovy/com/cloudbees/plugins/flow/AbortTest.groovy
Expand Up @@ -25,6 +25,10 @@ package com.cloudbees.plugins.flow

import hudson.model.Job
import hudson.model.Result
import jenkins.model.Jenkins
import hudson.model.Cause.UserIdCause;
import hudson.model.ParametersAction;
import hudson.model.StringParameterValue;

/**
* Tests that when a flow is aborted is it reported correctly.
Expand Down Expand Up @@ -150,4 +154,62 @@ class AbortTest extends DSLTestCase {
assertBuildStatus(Result.ABORTED, flow)
}

/**
* Tests that when a Flow is aborted it correctly aborts jobs that it queued.
*/
public void testThatAbortAbortsQueuedJobs() {
File f1 = new File("target/${getName()}_job1.lock")
f1.createNewFile()

Job job1 = createBlockingJob("job1", f1)

BuildFlow flow = new BuildFlow(Jenkins.instance, getName())
flow.concurrentBuild = true;
flow.onCreatedFromScratch()
flow.dsl = """ build("job1", param1: build.number) """

// Start an initially blocked job to to create a queue.
def sfr1 = job1.scheduleBuild2(0,new UserIdCause(), new ParametersAction(new StringParameterValue("param1", "first")));
def fr1 = sfr1.waitForStart()

println("Starting build flows...")
// Start three concurrent flows queueing up a job1,
// wait for the job1 to queue up before starting the next
// flow to ensure a consistent queue.
def queue = Jenkins.instance.queue;
def flows = []
for (i in 1..3) {
def scheduled = flow.scheduleBuild2(0)
def future = scheduled.waitForStart()
while (queue.getItems(job1).size() < i ) {
Thread.sleep(10L);
}
flows.add([flow:scheduled, future: future])
}

// abort the second flow
println("aborting flow #2...")
flows[1].future.oneOffExecutor.interrupt(Result.ABORTED)
println("aborting request sent...")
// wait for the flow to finish executing.
assertBuildStatus(Result.ABORTED, flows[1].flow.get())

// Release the blocked job
System.out.println("releasing jobs")
f1.delete()

waitUntilNoActivityUpTo(25000)

assertRan(job1, 3, Result.SUCCESS)

// Needs to assert that only the aborted build, (param1:2), is missing
// since no records exist when queued builds are cancelled.
assertHasParameter(job1.builds[2], 'param1', 'first')
assertHasParameter(job1.builds[1], 'param1', '1')
assertHasParameter(job1.builds[0], 'param1', '3')

// Assert that non aborted flows succeeded.
assertBuildStatusSuccess(flows[0].flow.get())
assertBuildStatusSuccess(flows[2].flow.get())
}
}

0 comments on commit 9711dc2

Please sign in to comment.