Skip to content

Commit

Permalink
Make it possible to include custom columns from TestActions in case, …
Browse files Browse the repository at this point in the history
…class and package tables (#503)
  • Loading branch information
jonaslind authored Mar 17, 2023
1 parent 1f21c40 commit 1be5936
Show file tree
Hide file tree
Showing 23 changed files with 385 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/main/java/hudson/tasks/junit/ClassResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ public String getChildTitle() {
return "Class Results";
}

@Override
public String getChildType() {
return "case";
}

@Exported(visibility=999)
@Override
public String getName() {
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/hudson/tasks/junit/PackageResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ public String getChildTitle() {
return Messages.PackageResult_getChildTitle();
}

@Override
public String getChildType() {
return "class";
}

// TODO: wait until stapler 1.60 to do this @Exported
@Override
public float getDuration() {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/hudson/tasks/junit/TestAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
* <li>index.jelly: included at the top of the test page</li>
* <li>summary.jelly: included in a collapsed panel on the test parent page</li>
* <li>badge.jelly: shown after the test link on the test parent page</li>
* <li>casetableheader.jelly: allows additional table headers to be shown in tables that list test methods</li>
* <li>classtableheader.jelly: allows additional table headers to be shown in tables that list test classes</li>
* <li>packagetableheader.jelly: allows additional table headers to be shown in tables that list test packages</li>
* <li>tablerow.jelly: allows additional table cells to be shown in tables that list test methods, classes and packages</li>
* </ul>
*
* @author tom
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/hudson/tasks/junit/TestResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ public String getChildTitle() {
return Messages.TestResult_getChildTitle();
}

@Override
public String getChildType() {
return "package";
}

@Exported(visibility=999)
@Override
public float getDuration() {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/hudson/tasks/test/TabulatedResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,14 @@ public TabulatedResult blockToTestResult(@NonNull PipelineBlockWithTests block,
public String getChildTitle() {
return "";
}

/**
* Get a simple name for the type of children the {@link #getChildren()} method returns, for example "case", "class"
* or "package".
*
* @return the type of children this result has, all lowercase.
*/
public String getChildType() {
return "";
}
}
6 changes: 6 additions & 0 deletions src/main/resources/hudson/tasks/junit/ClassResult/body.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ THE SOFTWARE.
<th class="pane-header">${%Test name}</th>
<th class="pane-header" style="width:6em">${%Duration}</th>
<th class="pane-header" style="width:6em">${%Status}</th>
<j:forEach var="tableheader" items="${it.testActions}">
<st:include it="${tableheader}" page="${it.childType}tableheader.jelly" optional="true"/>
</j:forEach>
</tr>
</thead>
<tbody>
Expand All @@ -50,6 +53,9 @@ THE SOFTWARE.
${pst.message}
</span>
</td>
<j:forEach var="tablerow" items="${p.testActions}">
<st:include it="${tablerow}" page="tablerow.jelly" optional="true"/>
</j:forEach>
</tr>
</j:forEach>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ THE SOFTWARE.
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:t="/lib/hudson/test">
<j:if test="${it.failCount!=0}">
<h2>${%All Failed Tests}</h2>
<table class="jenkins-table sortable">
<table class="jenkins-table sortable" id="failedtestresult">
<thead>
<tr>
<th class="pane-header">${%Test Name}</th>
<th class="pane-header" style="width:4em">${%Duration}</th>
<th class="pane-header" style="width:3em">${%Age}</th>
<j:forEach var="tableheader" items="${it.testActions}">
<st:include it="${tableheader}" page="casetableheader.jelly" optional="true"/>
</j:forEach>
</tr>
</thead>
<j:forEach var="f" items="${it.failedTests}" varStatus="i">
Expand All @@ -44,6 +47,9 @@ THE SOFTWARE.
<td class="pane" style="text-align:right;">
<a href="${rootURL}/${f.failedSinceRun.url}">${f.age}</a>
</td>
<j:forEach var="tablerow" items="${f.testActions}">
<st:include it="${tablerow}" page="tablerow.jelly" optional="true"/>
</j:forEach>
</tr>
</j:forEach>
</table>
Expand All @@ -64,6 +70,9 @@ THE SOFTWARE.
<th class="pane-header" style="width:3em; text-align:right; white-space:nowrap;">(${%diff})</th>
<th class="pane-header" style="width:5em; text-align:right">${%Total}</th>
<th class="pane-header" style="width:3em; text-align:right; white-space:nowrap;">(${%diff})</th>
<j:forEach var="tableheader" items="${it.testActions}">
<st:include it="${tableheader}" page="${it.childType}tableheader.jelly" optional="true"/>
</j:forEach>
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -94,6 +103,9 @@ THE SOFTWARE.
<td class="pane" style="text-align:right" data="${p.totalCount-prev.totalCount}">
${h.getDiffString2(p.totalCount-prev.totalCount)}
</td>
<j:forEach var="tablerow" items="${p.testActions}">
<st:include it="${tablerow}" page="tablerow.jelly" optional="true"/>
</j:forEach>
</tr>
</j:forEach>
</tbody>
Expand Down
113 changes: 113 additions & 0 deletions src/test/java/hudson/tasks/junit/CustomColumnsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package hudson.tasks.junit;

import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlTable;
import com.gargoylesoftware.htmlunit.html.HtmlTableCell;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Result;
import hudson.tasks.junit.rot13.Rot13Publisher;
import hudson.tasks.test.helper.WebClientFactory;
import org.apache.commons.lang3.tuple.Pair;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestBuilder;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;

/**
* Verifies that TestDataPublishers can contribute custom columns to html tables in result pages.
*/
public class CustomColumnsTest {

@Rule
public JenkinsRule jenkins = new JenkinsRule();

private FreeStyleProject project;

private static final String reportFileName = "junit-report-494.xml";

@Before
public void setUp() throws Exception {
project = jenkins.createFreeStyleProject("customcolumns");
JUnitResultArchiver archiver = new JUnitResultArchiver("*.xml");
archiver.setTestDataPublishers(Collections.singletonList(new Rot13Publisher()));
archiver.setSkipPublishingChecks(true);
project.getPublishersList().add(archiver);
project.getBuildersList().add(new TestBuilder() {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException {
build.getWorkspace().child(reportFileName).copyFrom(getClass().getResource(reportFileName));
return true;
}
});
FreeStyleBuild build = project.scheduleBuild2(0).get(5, TimeUnit.MINUTES);
jenkins.assertBuildStatus(Result.UNSTABLE, build);
}

@SafeVarargs
private void verifyThatTableContainsExpectedValues(String pathToPage, String tableId, String headerName,
Pair<String, String>... rowValues) throws Exception {

JenkinsRule.WebClient wc = WebClientFactory.createWebClientWithDisabledJavaScript(jenkins);
HtmlPage projectPage = wc.getPage(project);
jenkins.assertGoodStatus(projectPage);
HtmlPage classReportPage = wc.getPage(project, pathToPage);
jenkins.assertGoodStatus(classReportPage);

HtmlTable testResultTable = (HtmlTable) classReportPage.getFirstByXPath("//table[@id='" + tableId + "']");
List<HtmlTableCell> headerRowCells = testResultTable.getHeader().getRows().get(0).getCells();
int numberOfColumns = headerRowCells.size();
assertEquals(headerName, headerRowCells.get(numberOfColumns - 1).asNormalizedText());

for (int x = 0; x < rowValues.length; x++) {
List<HtmlTableCell> bodyRowCells = testResultTable.getBodies().get(0).getRows().get(x).getCells();
assertThat(bodyRowCells.get(0).asNormalizedText(), CoreMatchers.containsString(rowValues[x].getLeft()));
assertEquals(rowValues[x].getRight(), bodyRowCells.get(numberOfColumns - 1).asNormalizedText());
}
}

@Test
public void verifyThatCustomColumnIsAddedToTheTestsTableOnTheClassResultPage() throws Exception {
verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/AnExampleTestClass/",
"testresult", "ROT13 for cases on class page", Pair.of("testCaseA", "grfgPnfrN for case"), Pair.of(
"testCaseZ", "grfgPnfrM for case"));
}

@Test
public void verifyThatCustomColumnIsAddedToTheFailedTestsTableOnThePackageResultPage() throws Exception {
verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/", "failedtestresult",
"ROT13 for failed cases on package page", Pair.of("testCaseA", "grfgPnfrN for case"));
}

@Test
public void verifyThatCustomColumnIsAddedToTheClassesTableOnThePackageResultPage() throws Exception {
verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/", "testresult",
"ROT13 for all classes on package page", Pair.of("AnExampleTestClass", "NaRknzcyrGrfgPynff for class"));
}

@Test
public void verifyThatCustomColumnIsAddedToTheFailedTestsTableOnTheTestResultPage() throws Exception {
verifyThatTableContainsExpectedValues("/lastBuild/testReport/", "failedtestresult",
"ROT13 for failed cases on test page", Pair.of("testCaseA", "grfgPnfrN for case"));
}

@Test
public void verifyThatCustomColumnIsAddedToTheClassesTableOnTheTestResultPage() throws Exception {
verifyThatTableContainsExpectedValues("/lastBuild/testReport/", "testresult",
"ROT13 for all packages on test page", Pair.of("io.jenkins.example", "vb.wraxvaf.rknzcyr for package"));
}
}
9 changes: 9 additions & 0 deletions src/test/java/hudson/tasks/junit/rot13/Rot13CaseAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package hudson.tasks.junit.rot13;

public class Rot13CaseAction extends Rot13CipherAction {

public Rot13CaseAction(String ciphertext) {
super(ciphertext);
}

}
32 changes: 32 additions & 0 deletions src/test/java/hudson/tasks/junit/rot13/Rot13CipherAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package hudson.tasks.junit.rot13;

import hudson.tasks.junit.TestAction;

public abstract class Rot13CipherAction extends TestAction {

private final String ciphertext;

public Rot13CipherAction(String ciphertext) {
this.ciphertext = ciphertext;
}

@Override
public final String getIconFileName() {
return null;
}

@Override
public final String getDisplayName() {
return null;
}

@Override
public String getUrlName() {
return null;
}

public String getCiphertext() {
return ciphertext;
}

}
9 changes: 9 additions & 0 deletions src/test/java/hudson/tasks/junit/rot13/Rot13ClassAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package hudson.tasks.junit.rot13;

public class Rot13ClassAction extends Rot13CipherAction {

public Rot13ClassAction(String ciphertext) {
super(ciphertext);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package hudson.tasks.junit.rot13;

public class Rot13PackageAction extends Rot13CipherAction {

public Rot13PackageAction(String ciphertext) {
super(ciphertext);
}

}
Loading

0 comments on commit 1be5936

Please sign in to comment.