Skip to content

Commit

Permalink
[FIXED JENKINS-26964] Handle AbortException right
Browse files Browse the repository at this point in the history
(cherry picked from commit 625a22e)
  • Loading branch information
KostyaSha authored and olivergondza committed Jun 9, 2015
1 parent 7a2950b commit e18bde3
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 2 deletions.
7 changes: 5 additions & 2 deletions core/src/main/java/hudson/model/AbstractBuild.java
Expand Up @@ -720,6 +720,7 @@ protected final boolean performAllBuildSteps(BuildListener listener, Iterable<?
try {
if (!perform(bs,listener)) {
LOGGER.log(Level.FINE, "{0} : {1} failed", new Object[] {AbstractBuild.this, bs});
setResult(Result.FAILURE);
r = false;
}
} catch (Exception e) {
Expand All @@ -733,8 +734,10 @@ protected final boolean performAllBuildSteps(BuildListener listener, Iterable<?

private void reportError(BuildStep bs, Throwable e, BuildListener listener, boolean phase) {
String msg = "Publisher " + bs.getClass().getName() + " aborted due to exception";
e.printStackTrace(listener.error(msg));
LOGGER.log(WARNING, msg, e);
if (!(e instanceof AbortException)){
e.printStackTrace(listener.error(msg));
LOGGER.log(WARNING, msg, e);
}
if (phase) {
setResult(Result.FAILURE);
}
Expand Down
89 changes: 89 additions & 0 deletions test/src/test/java/hudson/model/FreestyleJobPublisherTest.java
@@ -0,0 +1,89 @@
package hudson.model;

import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Result;
import hudson.model.utils.AbortExceptionPublisher;
import hudson.model.utils.IOExceptionPublisher;
import hudson.model.utils.ResultWriterPublisher;
import hudson.model.utils.TrueFalsePublisher;
import hudson.tasks.ArtifactArchiver;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
* Freestyle publishers statuses tests
* @author Kanstantsin Shautsou
*/
public class FreestyleJobPublisherTest {
@Rule
public JenkinsRule j = new JenkinsRule();

/**
* Execute even one of publishers return false. Shows JENKINS-26964 bug.
*/
@Issue("JENKINS-26964")
@Test
public void testFreestyleWithFalsePublisher() throws Exception {
FreeStyleProject p = j.createFreeStyleProject();

p.getPublishersList().add(new TrueFalsePublisher(true)); // noop
p.getPublishersList().add(new TrueFalsePublisher(false)); // FAIL build with false
p.getPublishersList().add(new ResultWriterPublisher("result.txt")); //catch result to file
p.getPublishersList().add(new ArtifactArchiver("result.txt", "", false));

FreeStyleBuild b = p.scheduleBuild2(0).get();
assertEquals("Build must fail, because we used FalsePublisher", b.getResult(), Result.FAILURE);
File file = new File(b.getArtifactsDir(), "result.txt");
assertTrue("ArtifactArchiver is executed even prior publisher fails.", file.exists());
assertTrue("Second publisher must see FAILURE status", FileUtils.readFileToString(file).equals(Result.FAILURE.toString()));
}

/**
* Execute all publishers even one of them throws AbortException.
*/
@Test
public void testFreestyleWithExceptionPublisher() throws IOException, ExecutionException, InterruptedException {
FreeStyleProject p = j.createFreeStyleProject();

p.getPublishersList().add(new TrueFalsePublisher(true)); // noop
p.getPublishersList().add(new AbortExceptionPublisher()); // FAIL build with AbortException
p.getPublishersList().add(new ResultWriterPublisher("result.txt")); //catch result to file
p.getPublishersList().add(new ArtifactArchiver("result.txt", "", false));

FreeStyleBuild b = p.scheduleBuild2(0).get();
assertEquals("Build must fail, because we used FalsePublisher", b.getResult(), Result.FAILURE);
File file = new File(b.getArtifactsDir(), "result.txt");
assertTrue("ArtifactArchiver is executed even prior publisher fails.", file.exists());
assertTrue("Second publisher must see FAILURE status", FileUtils.readFileToString(file).equals(Result.FAILURE.toString()));
}

/**
* Execute all publishers even one of them throws any Exceptions.
*/
@Test
public void testFreestyleWithIOExceptionPublisher() throws IOException, ExecutionException, InterruptedException {
FreeStyleProject p = j.createFreeStyleProject();

p.getPublishersList().add(new TrueFalsePublisher(true)); // noop
p.getPublishersList().add(new IOExceptionPublisher()); // fail with IOException
p.getPublishersList().add(new ResultWriterPublisher("result.txt")); //catch result to file
p.getPublishersList().add(new ArtifactArchiver("result.txt", "", false));

FreeStyleBuild b = p.scheduleBuild2(0).get();
assertEquals("Build must fail, because we used FalsePublisher", b.getResult(), Result.FAILURE);
File file = new File(b.getArtifactsDir(), "result.txt");
assertTrue("ArtifactArchiver is executed even prior publisher fails.", file.exists());
assertTrue("Second publisher must see FAILURE status", FileUtils.readFileToString(file).equals(Result.FAILURE.toString()));
}
}
35 changes: 35 additions & 0 deletions test/src/test/java/hudson/model/utils/AbortExceptionPublisher.java
@@ -0,0 +1,35 @@
package hudson.model.utils;

import hudson.AbortException;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;

import java.io.IOException;

/**
* Publisher that throws AbortException
*/
public class AbortExceptionPublisher extends Recorder {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
throw new AbortException("Throwed AbortException from publisher!");
}

@Override
public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; }

@Extension
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
@Override
public String getDisplayName() { return "ThrowAbortExceptionRecorder"; }
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; }
}
}
35 changes: 35 additions & 0 deletions test/src/test/java/hudson/model/utils/IOExceptionPublisher.java
@@ -0,0 +1,35 @@
package hudson.model.utils;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;

import java.io.IOException;

/**
* Publisher that throw IOException
* @author Kanstantsin Shautsou
*/
public class IOExceptionPublisher extends Recorder {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
throw new IOException("Throwed IOException from publisher!");
}

@Override
public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; }

@Extension
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
@Override
public String getDisplayName() { return "Throw IOException Publisher"; }
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; }
}
}
47 changes: 47 additions & 0 deletions test/src/test/java/hudson/model/utils/ResultWriterPublisher.java
@@ -0,0 +1,47 @@
package hudson.model.utils;

import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;

import java.io.IOException;
import java.nio.charset.Charset;

/**
* Wrote build status to file
* @author Kanstantsin Shautsou
*/
public class ResultWriterPublisher extends Recorder {
private final String fileName;

public ResultWriterPublisher(String fileName) {
this.fileName = fileName;
}

@Override
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}

@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
FilePath file = build.getWorkspace().child(fileName);
file.write(build.getResult().toString(), Charset.defaultCharset().name());
return true;
}

@Extension
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
@Override
public String getDisplayName() { return "wrote result to file"; }
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; }
}
}
42 changes: 42 additions & 0 deletions test/src/test/java/hudson/model/utils/TrueFalsePublisher.java
@@ -0,0 +1,42 @@
package hudson.model.utils;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;
import org.kohsuke.stapler.DataBoundConstructor;

import java.io.IOException;

/**
* @author Kanstantsin Shautsou
*/
public class TrueFalsePublisher extends Recorder {
private final boolean b;

@DataBoundConstructor
public TrueFalsePublisher(boolean b) {
this.b = b;
}

@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
return b;
}

@Override
public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; }

@Extension
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
@Override
public String getDisplayName() { return "return true or false"; }
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; }
}
}

0 comments on commit e18bde3

Please sign in to comment.