Skip to content

Commit

Permalink
Fix JENKINS-18098
Browse files Browse the repository at this point in the history
  • Loading branch information
gboissinot committed Jan 1, 2014
1 parent b25b257 commit 7c05311
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 60 deletions.
17 changes: 17 additions & 0 deletions src/main/java/org/jenkinsci/plugins/xunit/ExtraConfiguration.java
@@ -0,0 +1,17 @@
package org.jenkinsci.plugins.xunit;

/**
* @author Gregory Boissinot
*/
public class ExtraConfiguration {

private final long testTimeMargin;

public ExtraConfiguration(long testTimeMargin) {
this.testTimeMargin = testTimeMargin;
}

public long getTestTimeMargin() {
return testTimeMargin;
}
}
Expand Up @@ -3,5 +3,5 @@
/** /**
* @author Gregory Boissinot * @author Gregory Boissinot
*/ */
public class NoTestException extends InterruptedException { public class NoFoundTestException extends InterruptedException {
} }
@@ -0,0 +1,7 @@
package org.jenkinsci.plugins.xunit;

/**
* @author Gregory Boissinot
*/
public class OldTestReportException extends InterruptedException {
}
19 changes: 16 additions & 3 deletions src/main/java/org/jenkinsci/plugins/xunit/XUnitBuilder.java
Expand Up @@ -26,6 +26,7 @@ public class XUnitBuilder extends Builder {
private TestType[] types; private TestType[] types;
private XUnitThreshold[] thresholds; private XUnitThreshold[] thresholds;
private int thresholdMode; private int thresholdMode;
private ExtraConfiguration extraConfiguration;


/** /**
* Computed * Computed
Expand All @@ -39,10 +40,15 @@ public XUnitBuilder(TestType[] types, XUnitThreshold[] thresholds) {
} }


@DataBoundConstructor @DataBoundConstructor
public XUnitBuilder(TestType[] tools, XUnitThreshold[] thresholds, int thresholdMode) { public XUnitBuilder(TestType[] tools, XUnitThreshold[] thresholds, int thresholdMode, String testTimeMargin) {
this.types = tools; this.types = tools;
this.thresholds = thresholds; this.thresholds = thresholds;
this.thresholdMode = thresholdMode; this.thresholdMode = thresholdMode;
long longTestTimeMargin = XUnitDefaultValues.TEST_REPORT_TIME_MARGING;
if (testTimeMargin != null && testTimeMargin.trim().length() != 0) {
longTestTimeMargin = Long.parseLong(testTimeMargin);
}
this.extraConfiguration = new ExtraConfiguration(longTestTimeMargin);
} }


public TestType[] getTypes() { public TestType[] getTypes() {
Expand All @@ -57,17 +63,24 @@ public int getThresholdMode() {
return thresholdMode; return thresholdMode;
} }


public ExtraConfiguration getExtraConfiguration() {
if (extraConfiguration == null) {
extraConfiguration = new ExtraConfiguration(XUnitDefaultValues.TEST_REPORT_TIME_MARGING);
}
return extraConfiguration;
}

@Override @Override
public boolean perform(final AbstractBuild<?, ?> build, Launcher launcher, final BuildListener listener) public boolean perform(final AbstractBuild<?, ?> build, Launcher launcher, final BuildListener listener)
throws InterruptedException, IOException { throws InterruptedException, IOException {
XUnitProcessor xUnitProcessor = new XUnitProcessor(types, thresholds, thresholdMode); XUnitProcessor xUnitProcessor = new XUnitProcessor(getTypes(), getThresholds(), getThresholdMode(), getExtraConfiguration());
return xUnitProcessor.performXUnit(false, build, listener); return xUnitProcessor.performXUnit(false, build, listener);
} }


public boolean performDryRun(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) public boolean performDryRun(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException { throws InterruptedException, IOException {
try { try {
XUnitProcessor xUnitProcessor = new XUnitProcessor(types, thresholds, thresholdMode); XUnitProcessor xUnitProcessor = new XUnitProcessor(getTypes(), getThresholds(), getThresholdMode(), getExtraConfiguration());
xUnitProcessor.performXUnit(true, build, listener); xUnitProcessor.performXUnit(true, build, listener);
} catch (Throwable t) { } catch (Throwable t) {
listener.getLogger().println("[ERROR] - There is an error: " + t.getCause().getMessage()); listener.getLogger().println("[ERROR] - There is an error: " + t.getCause().getMessage());
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/org/jenkinsci/plugins/xunit/XUnitDefaultValues.java
@@ -0,0 +1,13 @@
package org.jenkinsci.plugins.xunit;

/**
* @author Gregory Boissinot
*/
public class XUnitDefaultValues {

public static final String GENERATED_JUNIT_DIR = "generatedJUnitFiles";

public static final int MODE_PERCENT = 2;

public static final int TEST_REPORT_TIME_MARGING = 3000; //default to 3000ms
}
26 changes: 14 additions & 12 deletions src/main/java/org/jenkinsci/plugins/xunit/XUnitProcessor.java
Expand Up @@ -29,18 +29,16 @@
*/ */
public class XUnitProcessor { public class XUnitProcessor {


public static final String GENERATED_JUNIT_DIR = "generatedJUnitFiles";

private static final int MODE_PERCENT = 2;

private TestType[] types; private TestType[] types;
private XUnitThreshold[] thresholds; private XUnitThreshold[] thresholds;
private int thresholdMode; private int thresholdMode;
private ExtraConfiguration extraConfiguration;


public XUnitProcessor(TestType[] types, XUnitThreshold[] thresholds, int thresholdMode) { public XUnitProcessor(TestType[] types, XUnitThreshold[] thresholds, int thresholdMode, ExtraConfiguration extraConfiguration) {
this.types = types; this.types = types;
this.thresholds = thresholds; this.thresholds = thresholds;
this.thresholdMode = thresholdMode; this.thresholdMode = thresholdMode;
this.extraConfiguration = extraConfiguration;
} }


public boolean performXUnit(boolean dryRun, AbstractBuild<?, ?> build, BuildListener listener) public boolean performXUnit(boolean dryRun, AbstractBuild<?, ?> build, BuildListener listener)
Expand Down Expand Up @@ -111,16 +109,19 @@ private boolean performTests(XUnitLog xUnitLog, AbstractBuild<?, ?> build, Build
try { try {
result = getWorkspace(build).act(xUnitTransformer); result = getWorkspace(build).act(xUnitTransformer);
findTest = true; findTest = true;
} catch (NoTestException ne) { } catch (NoFoundTestException ne) {
xUnitLog.infoConsoleLogger("Fail BUILD."); xUnitLog.infoConsoleLogger("Failing BUILD.");
throw new StopTestProcessingException(); throw new StopTestProcessingException();
} catch (SkipTestException se) { } catch (SkipTestException se) {
xUnitLog.infoConsoleLogger("Skipping the metric tool processing."); xUnitLog.infoConsoleLogger("Skipping the metric tool processing.");
continue; continue;
} catch (OldTestReportException se) {
xUnitLog.infoConsoleLogger("Failing BUILD.");
throw new StopTestProcessingException();
} }


if (!result && xUnitToolInfo.isStopProcessingIfError()) { if (!result && xUnitToolInfo.isStopProcessingIfError()) {
xUnitLog.infoConsoleLogger("Fail BUILD because 'set build failed if errors' option is activated."); xUnitLog.infoConsoleLogger("Failing BUILD because 'set build failed if errors' option is activated.");
throw new StopTestProcessingException(); throw new StopTestProcessingException();
} }
} }
Expand Down Expand Up @@ -173,6 +174,7 @@ protected void configure() {
tool.isFailIfNotNew(), tool.isFailIfNotNew(),
tool.isDeleteOutputFiles(), tool.isStopProcessingIfError(), tool.isDeleteOutputFiles(), tool.isStopProcessingIfError(),
build.getTimeInMillis(), build.getTimeInMillis(),
this.extraConfiguration.getTestTimeMargin(),
(tool instanceof CustomType) ? getCustomStylesheet(tool, build, listener) : null); (tool instanceof CustomType) ? getCustomStylesheet(tool, build, listener) : null);


} }
Expand Down Expand Up @@ -282,7 +284,7 @@ private TestResult getTestResult(final AbstractBuild<?, ?> build,


public TestResult invoke(File ws, VirtualChannel channel) throws IOException { public TestResult invoke(File ws, VirtualChannel channel) throws IOException {
final long nowSlave = System.currentTimeMillis(); final long nowSlave = System.currentTimeMillis();
File generatedJunitDir = new File(ws, GENERATED_JUNIT_DIR); File generatedJunitDir = new File(ws, XUnitDefaultValues.GENERATED_JUNIT_DIR);
//Ignore return value //Ignore return value
generatedJunitDir.mkdirs(); generatedJunitDir.mkdirs();
FileSet fs = Util.createFileSet(generatedJunitDir, junitFilePattern); FileSet fs = Util.createFileSet(generatedJunitDir, junitFilePattern);
Expand Down Expand Up @@ -349,7 +351,7 @@ private Result processResultThreshold(XUnitLog log,
for (XUnitThreshold threshold : thresholds) { for (XUnitThreshold threshold : thresholds) {
log.infoConsoleLogger(String.format("Check '%s' threshold.", threshold.getDescriptor().getDisplayName())); log.infoConsoleLogger(String.format("Check '%s' threshold.", threshold.getDescriptor().getDisplayName()));
Result result; Result result;
if (MODE_PERCENT == thresholdMode) { if (XUnitDefaultValues.MODE_PERCENT == thresholdMode) {
result = threshold.getResultThresholdPercent(log, build, testResultAction, previousTestResultAction); result = threshold.getResultThresholdPercent(log, build, testResultAction, previousTestResultAction);
} else { } else {
result = threshold.getResultThresholdNumber(log, build, testResultAction, previousTestResultAction); result = threshold.getResultThresholdNumber(log, build, testResultAction, previousTestResultAction);
Expand All @@ -371,14 +373,14 @@ private void processDeletion(boolean dryRun, AbstractBuild<?, ?> build, XUnitLog
InputMetric inputMetric = tool.getInputMetric(); InputMetric inputMetric = tool.getInputMetric();


if (dryRun || tool.isDeleteOutputFiles()) { if (dryRun || tool.isDeleteOutputFiles()) {
getWorkspace(build).child(GENERATED_JUNIT_DIR + "/" + inputMetric.getToolName()).deleteRecursive(); getWorkspace(build).child(XUnitDefaultValues.GENERATED_JUNIT_DIR + "/" + inputMetric.getToolName()).deleteRecursive();
} else { } else {
//Mark the tool file parent directory to no deletion //Mark the tool file parent directory to no deletion
keepJUnitDirectory = true; keepJUnitDirectory = true;
} }
} }
if (!keepJUnitDirectory) { if (!keepJUnitDirectory) {
getWorkspace(build).child(GENERATED_JUNIT_DIR).deleteRecursive(); getWorkspace(build).child(XUnitDefaultValues.GENERATED_JUNIT_DIR).deleteRecursive();
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new XUnitException("Problem on deletion", ioe); throw new XUnitException("Problem on deletion", ioe);
Expand Down
19 changes: 16 additions & 3 deletions src/main/java/org/jenkinsci/plugins/xunit/XUnitPublisher.java
Expand Up @@ -33,6 +33,7 @@ public class XUnitPublisher extends Recorder implements DryRun, Serializable {
private TestType[] types; private TestType[] types;
private XUnitThreshold[] thresholds; private XUnitThreshold[] thresholds;
private int thresholdMode; private int thresholdMode;
private ExtraConfiguration extraConfiguration;


public XUnitPublisher(TestType[] types, XUnitThreshold[] thresholds) { public XUnitPublisher(TestType[] types, XUnitThreshold[] thresholds) {
this.types = types; this.types = types;
Expand All @@ -41,10 +42,15 @@ public XUnitPublisher(TestType[] types, XUnitThreshold[] thresholds) {
} }


@DataBoundConstructor @DataBoundConstructor
public XUnitPublisher(TestType[] tools, XUnitThreshold[] thresholds, int thresholdMode) { public XUnitPublisher(TestType[] tools, XUnitThreshold[] thresholds, int thresholdMode, String testTimeMargin) {
this.types = tools; this.types = tools;
this.thresholds = thresholds; this.thresholds = thresholds;
this.thresholdMode = thresholdMode; this.thresholdMode = thresholdMode;
long longTestTimeMargin = XUnitDefaultValues.TEST_REPORT_TIME_MARGING;
if (testTimeMargin != null && testTimeMargin.trim().length() != 0) {
longTestTimeMargin = Long.parseLong(testTimeMargin);
}
this.extraConfiguration = new ExtraConfiguration(longTestTimeMargin);
} }


public TestType[] getTypes() { public TestType[] getTypes() {
Expand All @@ -59,6 +65,13 @@ public int getThresholdMode() {
return thresholdMode; return thresholdMode;
} }


public ExtraConfiguration getExtraConfiguration() {
if (extraConfiguration == null) {
extraConfiguration = new ExtraConfiguration(XUnitDefaultValues.TEST_REPORT_TIME_MARGING);
}
return extraConfiguration;
}

@Override @Override
public Action getProjectAction(AbstractProject<?, ?> project) { public Action getProjectAction(AbstractProject<?, ?> project) {
JUnitResultArchiver jUnitResultArchiver = project.getPublishersList().get(JUnitResultArchiver.class); JUnitResultArchiver jUnitResultArchiver = project.getPublishersList().get(JUnitResultArchiver.class);
Expand All @@ -71,14 +84,14 @@ public Action getProjectAction(AbstractProject<?, ?> project) {
@Override @Override
public boolean perform(final AbstractBuild<?, ?> build, Launcher launcher, final BuildListener listener) public boolean perform(final AbstractBuild<?, ?> build, Launcher launcher, final BuildListener listener)
throws InterruptedException, IOException { throws InterruptedException, IOException {
XUnitProcessor xUnitProcessor = new XUnitProcessor(types, thresholds, thresholdMode); XUnitProcessor xUnitProcessor = new XUnitProcessor(getTypes(), getThresholds(), getThresholdMode(), getExtraConfiguration());
return xUnitProcessor.performXUnit(false, build, listener); return xUnitProcessor.performXUnit(false, build, listener);
} }


public boolean performDryRun(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) public boolean performDryRun(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException { throws InterruptedException, IOException {
try { try {
XUnitProcessor xUnitProcessor = new XUnitProcessor(types, thresholds, thresholdMode); XUnitProcessor xUnitProcessor = new XUnitProcessor(getTypes(), getThresholds(), getThresholdMode(), getExtraConfiguration());
xUnitProcessor.performXUnit(true, build, listener); xUnitProcessor.performXUnit(true, build, listener);
} catch (Throwable t) { } catch (Throwable t) {
listener.getLogger().println("[ERROR] - There is an error: " + t.getCause().getMessage()); listener.getLogger().println("[ERROR] - There is an error: " + t.getCause().getMessage());
Expand Down
Expand Up @@ -4,6 +4,7 @@
import hudson.Util; import hudson.Util;
import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FileSet;
import org.jenkinsci.plugins.xunit.OldTestReportException;


import java.io.File; import java.io.File;
import java.io.Serializable; import java.io.Serializable;
Expand Down Expand Up @@ -73,14 +74,14 @@ public List<String> findReports(XUnitToolInfo xUnitToolInfo, File parentPath, St
* @param workspace the root location of the file list * @param workspace the root location of the file list
* @return true if all files are new, false otherwise * @return true if all files are new, false otherwise
*/ */
public boolean checkIfFindsFilesNewFiles(XUnitToolInfo xUnitToolInfo, List<String> files, File workspace) { public void checkIfFindsFilesNewFiles(XUnitToolInfo xUnitToolInfo, List<String> files, File workspace) throws OldTestReportException {


if (xUnitToolInfo.isFailIfNotNew()) { if (xUnitToolInfo.isFailIfNotNew()) {
ArrayList<File> oldResults = new ArrayList<File>(); ArrayList<File> oldResults = new ArrayList<File>();
for (String value : files) { for (String value : files) {
File reportFile = new File(workspace, value); File reportFile = new File(workspace, value);
// if the file was not updated this build, that is a problem // if the file was not updated this build, that is a problem
if (xUnitToolInfo.getBuildTime() - 3000 > reportFile.lastModified()) { if (xUnitToolInfo.getBuildTime() - xUnitToolInfo.getTestTimeMargin() > reportFile.lastModified()) {
oldResults.add(reportFile); oldResults.add(reportFile);
} }
} }
Expand All @@ -94,7 +95,7 @@ public boolean checkIfFindsFilesNewFiles(XUnitToolInfo xUnitToolInfo, List<Strin
"Please keep the slave clock in sync with the master."; "Please keep the slave clock in sync with the master.";
xUnitLog.errorConsoleLogger(msg); xUnitLog.errorConsoleLogger(msg);
errorSystemLogger(msg); errorSystemLogger(msg);
return false; throw new OldTestReportException();
} }


StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
Expand All @@ -108,11 +109,9 @@ public boolean checkIfFindsFilesNewFiles(XUnitToolInfo xUnitToolInfo, List<Strin
String msg = stringBuilder.toString(); String msg = stringBuilder.toString();
xUnitLog.errorConsoleLogger(msg); xUnitLog.errorConsoleLogger(msg);
errorSystemLogger(msg); errorSystemLogger(msg);
return false; throw new OldTestReportException();
} }
} }

return true;
} }


/** /**
Expand Down
Expand Up @@ -24,9 +24,14 @@ public class XUnitToolInfo implements Serializable {


private final long buildTime; private final long buildTime;


private final long testTimeMargin;

private FilePath cusXSLFile; private FilePath cusXSLFile;


public XUnitToolInfo(FilePath userContentRoot, InputMetric inputMetric, String expandedPattern, Boolean skipNoTestFiles, Boolean failIfNotNew, Boolean deleteOutputFiles, Boolean stopProcessingIfError, long buildTime, FilePath cusXSLFile) { public XUnitToolInfo(FilePath userContentRoot, InputMetric inputMetric,
String expandedPattern, Boolean skipNoTestFiles, Boolean failIfNotNew,
Boolean deleteOutputFiles, Boolean stopProcessingIfError,
long buildTime, long testTimeMargin, FilePath cusXSLFile) {
this.userContentRoot = userContentRoot; this.userContentRoot = userContentRoot;
this.inputMetric = inputMetric; this.inputMetric = inputMetric;
this.expandedPattern = expandedPattern; this.expandedPattern = expandedPattern;
Expand All @@ -35,6 +40,7 @@ public XUnitToolInfo(FilePath userContentRoot, InputMetric inputMetric, String e
this.deleteOutputFiles = deleteOutputFiles; this.deleteOutputFiles = deleteOutputFiles;
this.stopProcessingIfError = stopProcessingIfError; this.stopProcessingIfError = stopProcessingIfError;
this.buildTime = buildTime; this.buildTime = buildTime;
this.testTimeMargin = testTimeMargin;
this.cusXSLFile = cusXSLFile; this.cusXSLFile = cusXSLFile;
} }


Expand Down Expand Up @@ -73,4 +79,8 @@ public boolean isStopProcessingIfError() {
public FilePath getUserContentRoot() { public FilePath getUserContentRoot() {
return userContentRoot; return userContentRoot;
} }

public long getTestTimeMargin() {
return testTimeMargin;
}
} }
Expand Up @@ -4,9 +4,10 @@
import hudson.FilePath; import hudson.FilePath;
import hudson.remoting.VirtualChannel; import hudson.remoting.VirtualChannel;
import hudson.util.IOException2; import hudson.util.IOException2;
import org.jenkinsci.plugins.xunit.NoTestException; import org.jenkinsci.plugins.xunit.NoFoundTestException;
import org.jenkinsci.plugins.xunit.OldTestReportException;
import org.jenkinsci.plugins.xunit.SkipTestException; import org.jenkinsci.plugins.xunit.SkipTestException;
import org.jenkinsci.plugins.xunit.XUnitProcessor; import org.jenkinsci.plugins.xunit.XUnitDefaultValues;


import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
Expand Down Expand Up @@ -51,7 +52,7 @@ void load(
public Boolean invoke(File ws, VirtualChannel channel) throws IOException, InterruptedException { public Boolean invoke(File ws, VirtualChannel channel) throws IOException, InterruptedException {
try { try {


File junitOutputDir = new File(ws, XUnitProcessor.GENERATED_JUNIT_DIR); File junitOutputDir = new File(ws, XUnitDefaultValues.GENERATED_JUNIT_DIR);
if (!junitOutputDir.exists() && !junitOutputDir.mkdirs()) { if (!junitOutputDir.exists() && !junitOutputDir.mkdirs()) {
String msg = "Can't create the path " + junitOutputDir + ". Maybe the directory already exists."; String msg = "Can't create the path " + junitOutputDir + ". Maybe the directory already exists.";
xUnitLog.warningConsoleLogger(msg); xUnitLog.warningConsoleLogger(msg);
Expand All @@ -73,14 +74,11 @@ public Boolean invoke(File ws, VirtualChannel channel) throws IOException, Inter
String msg = "No test reports found for the metric '" + metricName + "' with the resolved pattern '" + xUnitToolInfo.getExpandedPattern() + "'. Configuration error?."; String msg = "No test reports found for the metric '" + metricName + "' with the resolved pattern '" + xUnitToolInfo.getExpandedPattern() + "'. Configuration error?.";
xUnitLog.errorConsoleLogger(msg); xUnitLog.errorConsoleLogger(msg);
errorSystemLogger(msg); errorSystemLogger(msg);
throw new NoTestException(); throw new NoFoundTestException();
} }


//Checks the timestamp for each test file if the UI option is checked (true by default) //Checks the timestamp for each test file if the UI option is checked (true by default)
if (!xUnitReportProcessorService.checkIfFindsFilesNewFiles(xUnitToolInfo, resultFiles, ws)) { xUnitReportProcessorService.checkIfFindsFilesNewFiles(xUnitToolInfo, resultFiles, ws);
return false;
}



boolean atLeastOneWarningOrError = false; boolean atLeastOneWarningOrError = false;
for (String curFileName : resultFiles) { for (String curFileName : resultFiles) {
Expand Down Expand Up @@ -142,8 +140,10 @@ public Boolean invoke(File ws, VirtualChannel channel) throws IOException, Inter


} catch (SkipTestException se) { } catch (SkipTestException se) {
throw new SkipTestException(); throw new SkipTestException();
} catch (NoTestException se) { } catch (NoFoundTestException se) {
throw new NoTestException(); throw new NoFoundTestException();
} catch (OldTestReportException oe) {
throw new OldTestReportException();
} catch (Exception xe) { } catch (Exception xe) {
String msg = xe.getMessage(); String msg = xe.getMessage();
if (msg != null) { if (msg != null) {
Expand Down

0 comments on commit 7c05311

Please sign in to comment.