Skip to content

Commit

Permalink
Merge pull request #320 from mawinter69/master
Browse files Browse the repository at this point in the history
fix [JENKINS-45095]
  • Loading branch information
rsandell committed Aug 4, 2017
2 parents f7d6614 + 13109f5 commit 02e9f2b
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 1 deletion.
Expand Up @@ -121,6 +121,7 @@ protected void printTo(PrintWriter out) throws IOException {
out.println(" * Job: " + name);
out.println(" - Run: " + number);
out.println(" - Completed: " + en.isBuildCompleted());
out.println(" - Cancelled: " + en.isCancelled());
out.println(" - Result: " + result);
out.println(" - Triggered@ " + tsFormat.format(en.getTriggeredTimestamp()));
out.println(" - Started@ " + startedAt);
Expand Down
Expand Up @@ -401,6 +401,20 @@ public boolean isTriggered(Job project, GerritTriggeredEvent event) {
}
}

/**
* Sets the memory of the project to buildCompleted. Used when the entry is canceled in the Queue.
*
* @param project the project
* @param event the event
*/
public void setQueueCancelled(Job project, GerritTriggeredEvent event) {
if (project == null || event == null) {
return;
} else {
memory.cancelled(event, project);
}
}

/**
* Finds the GerritCause for a build if there is one.
*
Expand Down
Expand Up @@ -233,6 +233,26 @@ public synchronized void retriggered(
pb.reset(project);
}

/**
* Sets the status if a project to completed when queue is cancelled.
*
* @param event the event to be retriggered.
* @param project the project that has been retriggered.
*/
public synchronized void cancelled(GerritTriggeredEvent event, Job project) {
MemoryImprint pb = memory.get(event);
if (pb == null) {
//Shoudn't happen but just in case, keep the memory.
pb = new MemoryImprint(event);
memory.put(event, pb);
}
pb.set(project);
Entry entry = pb.getEntry(project);
entry.setCancelled(true);
entry.setBuildCompleted(true);
}


/**
* Removes the memory for the event.
*
Expand Down Expand Up @@ -347,7 +367,7 @@ public synchronized boolean isBuilding(GerritTriggeredEvent event, Job project)
if (entry.getBuild() != null) {
return !entry.isBuildCompleted();
} else {
return true;
return !entry.isCancelled();
}
}
}
Expand Down Expand Up @@ -781,6 +801,9 @@ public synchronized boolean wereAllBuildsNotBuilt() {
if (entry == null) {
continue;
}
if (entry.isCancelled()) {
continue;
}
Run build = entry.getBuild();
if (build == null) {
return false;
Expand All @@ -805,6 +828,7 @@ public static class Entry implements Cloneable {
private String project;
private String build;
private boolean buildCompleted;
private boolean cancelled;
private String customUrl;
private String unsuccessfulMessage;
private final long triggeredTimestamp;
Expand Down Expand Up @@ -833,6 +857,7 @@ private Entry(Job project, Run build) {
private Entry(Job project) {
this.project = project.getFullName();
buildCompleted = false;
cancelled = false;
this.triggeredTimestamp = System.currentTimeMillis();
}

Expand All @@ -851,6 +876,7 @@ public Entry(Entry copy) {
this.completedTimestamp = copy.completedTimestamp;
this.startedTimestamp = copy.startedTimestamp;
this.customUrl = copy.customUrl;
this.cancelled = copy.cancelled;
}

@Override
Expand Down Expand Up @@ -961,6 +987,23 @@ private void setBuildCompleted(boolean buildCompleted) {
}
}

/**
* If the build was cancelled.
* @return true if the build was cancelled while in the Queue
*/
public boolean isCancelled() {
return cancelled;
}

/**
* If the build was cancelled before if left the queue.
*
* @param cancelled true if the build was cancelled while in the queue.
*/
private void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}

/**
* The timestamp when {@link #setBuildCompleted(boolean)} was set to true.
* <code>null</code> indicates not completed yet.
Expand Down
@@ -0,0 +1,41 @@
package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger;

import hudson.Extension;
import hudson.model.TaskListener;
import hudson.model.Cause;
import hudson.model.Job;
import hudson.model.Queue.LeftItem;
import hudson.model.queue.QueueListener;
import hudson.util.LogTaskListener;

import java.util.logging.Level;
import java.util.logging.Logger;

import com.sonyericsson.hudson.plugins.gerrit.trigger.gerritnotifier.ToGerritRunListener;
import com.sonymobile.tools.gerrit.gerritevents.dto.events.GerritTriggeredEvent;

/**
* Listens to delete events in the Jenkins Queue to clean up the BuildMemory.
*/
@Extension
public class GerritQueueListener extends QueueListener {

private static final Logger logger = Logger.getLogger(GerritQueueListener.class.getName());

@Override
public void onLeft(LeftItem item) {
if (item.isCancelled() && item.task instanceof Job) {
for (Cause cause : item.getCauses()) {
if (cause instanceof GerritCause && !((GerritCause)cause).isSilentMode()) {
GerritCause gerritCause = (GerritCause)cause;
GerritTriggeredEvent event = gerritCause.getEvent();
ToGerritRunListener runListener = ToGerritRunListener.getInstance();
runListener.setQueueCancelled((Job)item.task, event);
TaskListener taskListener = new LogTaskListener(logger, Level.WARNING);
runListener.allBuildsCompleted(event, gerritCause, taskListener);
}
}
}
}

}
Expand Up @@ -53,6 +53,7 @@ l.layout(title: _("Build Coordination - Gerrit Trigger Diagnostics"), norefresh:
th(id: 'hJob', align: "left", _('Job'))
th(id: 'hRun', align: "left", _('Run #'))
th(id: 'hCompleted', align: "left", _('Completed'))
th(id: 'hCancelled', align: "left", _('Cancelled'))
th(id: 'hResult', align: "left", _('Result'))
th(id: 'hTriggeredTs', align: "left", _('Triggered@'))
th(id: 'hStartedTs', align: "left", _('Started@'))
Expand Down Expand Up @@ -89,6 +90,13 @@ l.layout(title: _("Build Coordination - Gerrit Trigger Diagnostics"), norefresh:
raw('&nbsp;')
}
}
td(headers: "hCancelled ${eventHeaderId}") {
if (entry.cancelled) {
strong(_('Y'))
} else {
raw('&nbsp;')
}
}
td(headers: "hResult ${eventHeaderId}") {
if (run != null && run.result != null) {
strong(run.result.toString())
Expand Down
Expand Up @@ -312,6 +312,20 @@ public void testCompleted() {
assertTrue(instance.isAllBuildsCompleted(event));
}


/**
* test.
*/
@Test
public void testCancelled() {
System.out.println("cancelled");
PatchsetCreated event = Setup.createPatchsetCreated();

BuildMemory instance = new BuildMemory();
instance.cancelled(event, project);
assertTrue(instance.isAllBuildsCompleted(event));
}

/**
* test.
*/
Expand Down
@@ -0,0 +1,142 @@
/*
* The MIT License
*
* Copyright 2010 Sony Ericsson Mobile Communications. All rights reserved.
* Copyright 2012 Sony Mobile Communications AB. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger;

import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Queue;
import hudson.model.Queue.Item;
import hudson.model.queue.QueueTaskFuture;

import java.util.concurrent.TimeUnit;

import jenkins.model.Jenkins;

import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import com.sonyericsson.hudson.plugins.gerrit.trigger.gerritnotifier.ToGerritRunListener;
import com.sonyericsson.hudson.plugins.gerrit.trigger.mock.Setup;
import com.sonymobile.tools.gerrit.gerritevents.dto.events.PatchsetCreated;

/**
* Tests for {@link ToGerritRunListener}.
*
* @author Robert Sandell &lt;robert.sandell@sonyericsson.com&gt;
*/
public class GerritQueueListenerTest {

private static final int TIMEOUT_SECONDS = 60;
private static final int QUIET_PERIOD = 5;

/**
* Jenkins rule instance.
*/
// CS IGNORE VisibilityModifier FOR NEXT 3 LINES. REASON: Mocks tests.
@Rule
public JenkinsRule jenkinsRule = new JenkinsRule();

/**
* Tests that event is properly removed if only one project is triggered
* which is cancelled while in the queue.
*
* @throws Exception if something goes wrong
*/
@Test
public void testCancelledQueueItemIsOnlyTriggeredProject() throws Exception {
FreeStyleProject project = jenkinsRule.createFreeStyleProject();
PatchsetCreated event = Setup.createPatchsetCreated();
final GerritCause gerritCause = new GerritCause(event, false);

ToGerritRunListener runListener = ToGerritRunListener.getInstance();
runListener.onTriggered(project, event);
project.scheduleBuild2(QUIET_PERIOD, gerritCause);

Item item = waitForBlockedItem(project, TIMEOUT_SECONDS);
Queue queue = jenkinsRule.getInstance().getQueue();
queue.doCancelItem(item.getId());
assertThat(queue.isEmpty(), equalTo(true));
assertThat(project.getBuilds().size(), equalTo(0));
assertThat(runListener.isBuilding(event), equalTo(false));
}

/**
* Tests that event is properly removed if only two different projects are triggered
* and one of them is cancelled while in the queue.
*
* @throws Exception if something goes wrong
*/
@Test
public void testCancelledOneQueueItemOfTwo() throws Exception {
FreeStyleProject project = jenkinsRule.createFreeStyleProject();
FreeStyleProject project2 = jenkinsRule.createFreeStyleProject();
PatchsetCreated event = Setup.createPatchsetCreated();
final GerritCause gerritCause = new GerritCause(event, false);

ToGerritRunListener runListener = ToGerritRunListener.getInstance();
runListener.onTriggered(project, event);
runListener.onTriggered(project2, event);
project.scheduleBuild2(QUIET_PERIOD, gerritCause);
QueueTaskFuture<FreeStyleBuild> future2 = project2.scheduleBuild2(QUIET_PERIOD, gerritCause);

Item item = waitForBlockedItem(project, TIMEOUT_SECONDS);
Queue queue = jenkinsRule.getInstance().getQueue();
queue.doCancelItem(item.getId());
FreeStyleBuild build = future2.get();
assertThat(queue.isEmpty(), equalTo(true));
assertThat(project.getBuilds().size(), equalTo(0));
assertThat(project2.getBuilds().size(), equalTo(1));
assertThat(runListener.isBuilding(event), equalTo(false));
}

/**
* Waits that the given project shows up in the queue and that it is blocked.
*
* @param project The project to wait for
* @param timeout seconds to wait before aborting
* @return the found item, null if the item didn't show up in the queue until timeout
* @throws InterruptedException if interrupted
*/
private Item waitForBlockedItem(FreeStyleProject project, int timeout) throws InterruptedException {
Queue jenkinsQueue = Jenkins.getInstance().getQueue();
Item queueItem = null;

int elapsedSeconds = 0;
while (elapsedSeconds <= timeout) {
queueItem = jenkinsQueue.getItem(project);
if (queueItem != null) {
return queueItem;
}
TimeUnit.SECONDS.sleep(1);
elapsedSeconds++;
}
return queueItem;
}

}

0 comments on commit 02e9f2b

Please sign in to comment.