-
Notifications
You must be signed in to change notification settings - Fork 340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix NoSuchFileException due to spaces in file paths in JUnitResultArc… #663
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,10 @@ | |
import io.jenkins.plugins.junit.storage.JunitTestResultStorage; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.Comparator; | ||
import java.util.List; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import jenkins.MasterToSlaveFileCallable; | ||
|
@@ -58,11 +62,12 @@ | |
private final boolean keepTestNames; | ||
|
||
private final boolean skipOldReports; | ||
private final boolean sortTestResultsByTimestamp; | ||
|
||
/** Generally unused, but present for extension compatibility. */ | ||
@Deprecated | ||
public JUnitParser() { | ||
this(false, false, false, false); | ||
this(StdioRetention.DEFAULT, false, false, false, false, false); | ||
} | ||
|
||
/** | ||
|
@@ -71,42 +76,60 @@ | |
*/ | ||
@Deprecated | ||
public JUnitParser(boolean keepLongStdio) { | ||
this(keepLongStdio, false, false, false); | ||
this(StdioRetention.fromKeepLongStdio(keepLongStdio), false, false, false, false); | ||
} | ||
|
||
/** | ||
* @param keepLongStdio if true, retain a suite's complete stdout/stderr even if this is huge and the suite passed | ||
* @param allowEmptyResults if true, empty results are allowed | ||
* @since 1.10 | ||
*/ | ||
@Deprecated | ||
public JUnitParser(boolean keepLongStdio, boolean allowEmptyResults) { | ||
this(StdioRetention.fromKeepLongStdio(keepLongStdio), false, allowEmptyResults, false, false); | ||
this(StdioRetention.fromKeepLongStdio(keepLongStdio), false, allowEmptyResults, false, false, false); | ||
} | ||
|
||
@Deprecated | ||
public JUnitParser( | ||
boolean keepLongStdio, boolean keepProperties, boolean allowEmptyResults, boolean skipOldReports) { | ||
this(StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, allowEmptyResults, skipOldReports, false); | ||
this( | ||
StdioRetention.fromKeepLongStdio(keepLongStdio), | ||
keepProperties, | ||
allowEmptyResults, | ||
skipOldReports, | ||
false, | ||
false); | ||
} | ||
|
||
@Deprecated | ||
public JUnitParser( | ||
StdioRetention stdioRetention, boolean keepProperties, boolean allowEmptyResults, boolean skipOldReports) { | ||
this(stdioRetention, keepProperties, allowEmptyResults, skipOldReports, false); | ||
this(stdioRetention, keepProperties, allowEmptyResults, skipOldReports, false, false); | ||
} | ||
|
||
@Deprecated | ||
public JUnitParser( | ||
StdioRetention stdioRetention, | ||
boolean keepProperties, | ||
boolean allowEmptyResults, | ||
boolean skipOldReports, | ||
boolean keepTestNames) { | ||
this(stdioRetention, keepProperties, allowEmptyResults, skipOldReports, keepTestNames, false); | ||
} | ||
// New Constructor with the additional parameter | ||
public JUnitParser( | ||
StdioRetention stdioRetention, | ||
boolean keepProperties, | ||
boolean allowEmptyResults, | ||
boolean skipOldReports, | ||
boolean keepTestNames, | ||
boolean sortTestResultsByTimestamp) { | ||
this.stdioRetention = stdioRetention; | ||
this.keepProperties = keepProperties; | ||
this.allowEmptyResults = allowEmptyResults; | ||
this.keepTestNames = keepTestNames; | ||
this.skipOldReports = skipOldReports; | ||
this.keepTestNames = keepTestNames; | ||
this.sortTestResultsByTimestamp = sortTestResultsByTimestamp; | ||
} | ||
|
||
@Override | ||
|
@@ -152,7 +175,8 @@ | |
keepTestNames, | ||
pipelineTestDetails, | ||
listener, | ||
skipOldReports)); | ||
skipOldReports, | ||
sortTestResultsByTimestamp)); | ||
} | ||
|
||
public TestResultSummary summarizeResult( | ||
|
@@ -174,7 +198,8 @@ | |
pipelineTestDetails, | ||
listener, | ||
storage.createRemotePublisher(build), | ||
skipOldReports)); | ||
skipOldReports, | ||
sortTestResultsByTimestamp)); | ||
} | ||
|
||
private abstract static class ParseResultCallable<T> extends MasterToSlaveFileCallable<T> { | ||
|
@@ -194,6 +219,7 @@ | |
private final TaskListener listener; | ||
|
||
private boolean skipOldReports; | ||
private final boolean sortTestResultsByTimestamp; | ||
|
||
private ParseResultCallable( | ||
String testResults, | ||
|
@@ -204,7 +230,8 @@ | |
boolean keepTestNames, | ||
PipelineTestDetails pipelineTestDetails, | ||
TaskListener listener, | ||
boolean skipOldReports) { | ||
boolean skipOldReports, | ||
boolean sortTestResultsByTimestamp) { | ||
this.buildStartTimeInMillis = build.getStartTimeInMillis(); | ||
this.buildTimeInMillis = build.getTimeInMillis(); | ||
this.testResults = testResults; | ||
|
@@ -216,6 +243,7 @@ | |
this.pipelineTestDetails = pipelineTestDetails; | ||
this.listener = listener; | ||
this.skipOldReports = skipOldReports; | ||
this.sortTestResultsByTimestamp = sortTestResultsByTimestamp; | ||
} | ||
|
||
@Override | ||
|
@@ -226,7 +254,35 @@ | |
TestResult result; | ||
String[] files = ds.getIncludedFiles(); | ||
if (files.length > 0) { | ||
// not sure we can rely seriously on those timestamp so let's take the smaller one... | ||
// New sorting logic starts here | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't use words like |
||
List<File> fileList = new ArrayList<>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from here to line 279 it could all be expressed more simplify using a stream. roughly (pseudocode): files.stream()
.map(file => new File...)
.sorted(sortFunction handling if variable set)
.map(file -> back to relative path)
.collect(toList() maybe)
.toArray() |
||
for (String fileName : files) { | ||
fileList.add(new File(ds.getBasedir(), fileName)); | ||
} | ||
|
||
if (sortTestResultsByTimestamp) { | ||
Collections.sort(fileList, Comparator.comparingLong(File::lastModified)); | ||
} else { | ||
Collections.sort(fileList, Comparator.comparing(File::getName)); | ||
} | ||
|
||
// Convert back to String array with paths relative to the base directory | ||
String[] sortedFiles = new String[fileList.size()]; | ||
String baseDirPath = ds.getBasedir().getAbsolutePath(); | ||
for (int i = 0; i < fileList.size(); i++) { | ||
String absolutePath = fileList.get(i).getAbsolutePath(); | ||
if (absolutePath.startsWith(baseDirPath)) { | ||
sortedFiles[i] = absolutePath.substring(baseDirPath.length() + 1); | ||
} else { | ||
sortedFiles[i] = absolutePath; | ||
} | ||
} | ||
|
||
// Update the DirectoryScanner with the sorted files | ||
ds.setIncludes(sortedFiles); | ||
|
||
// Continue with existing processing logic | ||
// Not sure we can rely seriously on those timestamps so let's take the smaller one... | ||
long filesTimestamp = Math.min(buildStartTimeInMillis, buildTimeInMillis); | ||
// previous mode buildStartTimeInMillis + (nowSlave - nowMaster); | ||
if (LOGGER.isLoggable(Level.FINE)) { | ||
|
@@ -270,7 +326,8 @@ | |
boolean keepTestNames, | ||
PipelineTestDetails pipelineTestDetails, | ||
TaskListener listener, | ||
boolean skipOldReports) { | ||
boolean skipOldReports, | ||
boolean sortTestResultsByTimestamp) { | ||
super( | ||
testResults, | ||
build, | ||
|
@@ -280,7 +337,8 @@ | |
keepTestNames, | ||
pipelineTestDetails, | ||
listener, | ||
skipOldReports); | ||
skipOldReports, | ||
sortTestResultsByTimestamp); | ||
} | ||
|
||
@Override | ||
|
@@ -303,7 +361,8 @@ | |
PipelineTestDetails pipelineTestDetails, | ||
TaskListener listener, | ||
JunitTestResultStorage.RemotePublisher publisher, | ||
boolean skipOldReports) { | ||
boolean skipOldReports, | ||
boolean sortTestResultsByTimestamp) { | ||
super( | ||
testResults, | ||
build, | ||
|
@@ -313,7 +372,8 @@ | |
keepTestNames, | ||
pipelineTestDetails, | ||
listener, | ||
skipOldReports); | ||
skipOldReports, | ||
sortTestResultsByTimestamp); | ||
this.publisher = publisher; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -173,7 +173,8 @@ private static TestResult parse( | |||
task.isKeepProperties(), | ||||
task.isAllowEmptyResults(), | ||||
task.isSkipOldReports(), | ||||
task.isKeepTestNames()) | ||||
task.isKeepTestNames(), | ||||
task.isSortTestResultsByTimestamp()) | ||||
.parseResult(expandedTestResults, run, pipelineTestDetails, workspace, launcher, listener); | ||||
} | ||||
|
||||
|
@@ -189,7 +190,7 @@ protected TestResult parse( | |||
} | ||||
|
||||
@Override | ||||
public void perform(Run build, FilePath workspace, Launcher launcher, TaskListener listener) | ||||
public void perform(Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener) | ||||
throws InterruptedException, IOException { | ||||
if (parseAndSummarize(this, null, build, workspace, launcher, listener).getFailCount() > 0 | ||||
&& !skipMarkingBuildUnstable) { | ||||
|
@@ -288,7 +289,8 @@ public static TestResultSummary parseAndSummarize( | |||
task.isKeepProperties(), | ||||
task.isAllowEmptyResults(), | ||||
task.isSkipOldReports(), | ||||
task.isKeepTestNames()) | ||||
task.isKeepTestNames(), | ||||
task.isSortTestResultsByTimestamp()) | ||||
.summarizeResult(testResults, build, pipelineTestDetails, workspace, launcher, listener, storage); | ||||
} | ||||
|
||||
|
@@ -498,6 +500,11 @@ public boolean isSkipPublishingChecks() { | |||
return skipPublishingChecks; | ||||
} | ||||
|
||||
@DataBoundSetter | ||||
public final void setAllowEmptyResults(boolean allowEmptyResults) { | ||||
this.allowEmptyResults = allowEmptyResults; | ||||
} | ||||
|
||||
@DataBoundSetter | ||||
public void setSkipPublishingChecks(boolean skipPublishingChecks) { | ||||
this.skipPublishingChecks = skipPublishingChecks; | ||||
|
@@ -513,11 +520,6 @@ public void setChecksName(String checksName) { | |||
this.checksName = checksName; | ||||
} | ||||
|
||||
@DataBoundSetter | ||||
public final void setAllowEmptyResults(boolean allowEmptyResults) { | ||||
this.allowEmptyResults = allowEmptyResults; | ||||
} | ||||
|
||||
public boolean isSkipMarkingBuildUnstable() { | ||||
return skipMarkingBuildUnstable; | ||||
} | ||||
|
@@ -539,6 +541,20 @@ public void setSkipOldReports(boolean skipOldReports) { | |||
|
||||
private static final long serialVersionUID = 1L; | ||||
|
||||
@Override | ||||
public boolean isSortTestResultsByTimestamp() { | ||||
// Return the appropriate value or a default (e.g., false) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
return sortTestResultsByTimestamp; | ||||
} | ||||
|
||||
// Add the field and setter if needed | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
private boolean sortTestResultsByTimestamp; | ||||
|
||||
@DataBoundSetter | ||||
public void setSortTestResultsByTimestamp(boolean sortTestResultsByTimestamp) { | ||||
this.sortTestResultsByTimestamp = sortTestResultsByTimestamp; | ||||
} | ||||
|
||||
@Extension | ||||
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> { | ||||
@Override | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,9 +58,11 @@ | |
import hudson.tasks.test.helper.WebClientFactory; | ||
import hudson.util.HttpResponses; | ||
import java.io.File; | ||
import java.io.FileNotFoundException; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.io.PrintWriter; | ||
import java.net.URL; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
|
@@ -482,16 +484,24 @@ public void testXxe() throws Exception { | |
String oobInUserContentLink = j.getURL() + "userContent/oob.xml"; | ||
String triggerLink = j.getURL() + "triggerMe"; | ||
|
||
String xxeFile = this.getClass().getResource("testXxe-xxe.xml").getFile(); | ||
String xxeFileContent = FileUtils.readFileToString(new File(xxeFile), StandardCharsets.UTF_8); | ||
URL xxeResourceUrl = this.getClass().getResource("testXxe-xxe.xml"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these changes related to your change? You can submit them separately with reasoning if not |
||
if (xxeResourceUrl == null) { | ||
throw new FileNotFoundException("Resource 'testXxe-xxe.xml' not found"); | ||
} | ||
File xxeFile = new File(xxeResourceUrl.toURI()); | ||
String xxeFileContent = FileUtils.readFileToString(xxeFile, StandardCharsets.UTF_8); | ||
String adaptedXxeFileContent = xxeFileContent.replace("$OOB_LINK$", oobInUserContentLink); | ||
|
||
String oobFile = this.getClass().getResource("testXxe-oob.xml").getFile(); | ||
String oobFileContent = FileUtils.readFileToString(new File(oobFile), StandardCharsets.UTF_8); | ||
URL oobResourceUrl = this.getClass().getResource("testXxe-oob.xml"); | ||
if (oobResourceUrl == null) { | ||
throw new FileNotFoundException("Resource 'testXxe-oob.xml' not found"); | ||
} | ||
File oobFile = new File(oobResourceUrl.toURI()); | ||
String oobFileContent = FileUtils.readFileToString(oobFile, StandardCharsets.UTF_8); | ||
String adaptedOobFileContent = oobFileContent.replace("$TARGET_URL$", triggerLink); | ||
|
||
File userContentDir = new File(j.jenkins.getRootDir(), "userContent"); | ||
FileUtils.writeStringToFile(new File(userContentDir, "oob.xml"), adaptedOobFileContent); | ||
FileUtils.writeStringToFile(new File(userContentDir, "oob.xml"), adaptedOobFileContent, StandardCharsets.UTF_8); | ||
|
||
FreeStyleProject project = j.createFreeStyleProject(); | ||
DownloadBuilder builder = new DownloadBuilder(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please don't add comments like this