package org.jenkinsci.plugins.quarantine;
import hudson.AbortException;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.TaskListener;
import hudson.model.Run;
import hudson.model.Result;
import hudson.tasks.junit.JUnitParser;
import hudson.tasks.junit.TestResult;
import hudson.tasks.junit.TestDataPublisher;
import hudson.tasks.junit.TestResultAction;
import hudson.tasks.junit.TestResultAction.Data;
import hudson.tasks.junit.CaseResult;
import hudson.tasks.junit.JUnitResultArchiver;
import org.kohsuke.stapler.DataBoundConstructor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class QuarantinableJUnitResultArchiver extends JUnitResultArchiver {
@DataBoundConstructor
public QuarantinableJUnitResultArchiver(String testResults) {
super(testResults);
}
/**
* Because build results can only be made worse, we can't just run another
* recorder straight after the JUnitResultArchiver. So we clone-and-own the
* {@link JUnitResultArchiver#perform(AbstractBuild, Launcher, BuildListener)}
* method here so we can inspect the quarantine before making the PASS/FAIL
* decision
*
* The build is only failed if there are failing tests that have not been put
* in quarantine
*/
@Override
public void perform(Run build, FilePath workspace, Launcher launcher,
TaskListener listener) throws InterruptedException, IOException {
listener.getLogger().println(hudson.tasks.junit.Messages.JUnitResultArchiver_Recording());
final String testResults = build.getEnvironment(listener).expand(getTestResults());
// ideally, we'd use parse() here, but it's been made private... :-(
TestResult result = new JUnitParser(isKeepLongStdio()).parseResult(testResults, build, workspace, launcher, listener);
synchronized (build) {
TestResultAction action = build.getAction(TestResultAction.class);
try {
action = new TestResultAction(build, result, listener);
} catch (NullPointerException npe) {
throw new AbortException(Messages.QuarantinableJUnitResultArchiver_BadXML(testResults));
}
result.freeze(action);
action.setHealthScaleFactor(getHealthScaleFactor()); // overwrites previous value if appending
if (result.isEmpty()) {
if (build.getResult() == Result.FAILURE) {
// most likely a build failed before it gets to the test phase.
// don't report confusing error message.
return;
}
// most likely a configuration error in the job - e.g. false pattern to match the JUnit result files
throw new AbortException(hudson.tasks.junit.Messages.JUnitResultArchiver_ResultIsEmpty());
}
// TODO: Move into JUnitParser [BUG 3123310]
// FIXME: ideally, we'd use action.getData() so we can add to the data, but it's not accessible.
// create a new list of data - not sure what the implications are, but that's how the quarantine
// plugin worked before
List<Data> data = new ArrayList<Data>();
if (getTestDataPublishers() != null) {
for (TestDataPublisher tdp : getTestDataPublishers()) {
Data d = tdp.contributeTestData(build, workspace, launcher, listener, result);
if (d != null) {
data.add(d);
}
}
action.setData(data);
}
build.addAction(action);
if (action.getResult().getFailCount() > 0)
{
int quarantined = 0;
for (CaseResult case_result : action.getResult().getFailedTests()) {
QuarantineTestAction quarantineAction = case_result.getTestAction(QuarantineTestAction.class);
if (quarantineAction != null) {
if (quarantineAction.isQuarantined()) {
listener.getLogger().println("[Quarantine]: " + case_result.getFullName() + " failed but is quarantined");
quarantined++;
}
}
}
int remaining = action.getResult().getFailCount() - quarantined;
listener.getLogger().println("[Quarantine]: " + remaining + " unquarantined failures remaining");
if (remaining > 0)
build.setResult(Result.UNSTABLE);
}
}
}
@Extension
public static class DescriptorImpl extends JUnitResultArchiver.DescriptorImpl {
public String getDisplayName() {
return Messages.QuarantinableJUnitResultArchiver_DisplayName();
}
}
}