Skip to content

Commit 1be5936

Browse files
authored
Make it possible to include custom columns from TestActions in case, class and package tables (#503)
1 parent 1f21c40 commit 1be5936

File tree

23 files changed

+385
-1
lines changed

23 files changed

+385
-1
lines changed

src/main/java/hudson/tasks/junit/ClassResult.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ public String getChildTitle() {
102102
return "Class Results";
103103
}
104104

105+
@Override
106+
public String getChildType() {
107+
return "case";
108+
}
109+
105110
@Exported(visibility=999)
106111
@Override
107112
public String getName() {

src/main/java/hudson/tasks/junit/PackageResult.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ public String getChildTitle() {
121121
return Messages.PackageResult_getChildTitle();
122122
}
123123

124+
@Override
125+
public String getChildType() {
126+
return "class";
127+
}
128+
124129
// TODO: wait until stapler 1.60 to do this @Exported
125130
@Override
126131
public float getDuration() {

src/main/java/hudson/tasks/junit/TestAction.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
* <li>index.jelly: included at the top of the test page</li>
3434
* <li>summary.jelly: included in a collapsed panel on the test parent page</li>
3535
* <li>badge.jelly: shown after the test link on the test parent page</li>
36+
* <li>casetableheader.jelly: allows additional table headers to be shown in tables that list test methods</li>
37+
* <li>classtableheader.jelly: allows additional table headers to be shown in tables that list test classes</li>
38+
* <li>packagetableheader.jelly: allows additional table headers to be shown in tables that list test packages</li>
39+
* <li>tablerow.jelly: allows additional table cells to be shown in tables that list test methods, classes and packages</li>
3640
* </ul>
3741
*
3842
* @author tom

src/main/java/hudson/tasks/junit/TestResult.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,11 @@ public String getChildTitle() {
479479
return Messages.TestResult_getChildTitle();
480480
}
481481

482+
@Override
483+
public String getChildType() {
484+
return "package";
485+
}
486+
482487
@Exported(visibility=999)
483488
@Override
484489
public float getDuration() {

src/main/java/hudson/tasks/test/TabulatedResult.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,14 @@ public TabulatedResult blockToTestResult(@NonNull PipelineBlockWithTests block,
121121
public String getChildTitle() {
122122
return "";
123123
}
124+
125+
/**
126+
* Get a simple name for the type of children the {@link #getChildren()} method returns, for example "case", "class"
127+
* or "package".
128+
*
129+
* @return the type of children this result has, all lowercase.
130+
*/
131+
public String getChildType() {
132+
return "";
133+
}
124134
}

src/main/resources/hudson/tasks/junit/ClassResult/body.jelly

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ THE SOFTWARE.
3232
<th class="pane-header">${%Test name}</th>
3333
<th class="pane-header" style="width:6em">${%Duration}</th>
3434
<th class="pane-header" style="width:6em">${%Status}</th>
35+
<j:forEach var="tableheader" items="${it.testActions}">
36+
<st:include it="${tableheader}" page="${it.childType}tableheader.jelly" optional="true"/>
37+
</j:forEach>
3538
</tr>
3639
</thead>
3740
<tbody>
@@ -50,6 +53,9 @@ THE SOFTWARE.
5053
${pst.message}
5154
</span>
5255
</td>
56+
<j:forEach var="tablerow" items="${p.testActions}">
57+
<st:include it="${tablerow}" page="tablerow.jelly" optional="true"/>
58+
</j:forEach>
5359
</tr>
5460
</j:forEach>
5561
</tbody>

src/main/resources/hudson/tasks/test/MetaTabulatedResult/body.jelly

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,15 @@ THE SOFTWARE.
2727
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:t="/lib/hudson/test">
2828
<j:if test="${it.failCount!=0}">
2929
<h2>${%All Failed Tests}</h2>
30-
<table class="jenkins-table sortable">
30+
<table class="jenkins-table sortable" id="failedtestresult">
3131
<thead>
3232
<tr>
3333
<th class="pane-header">${%Test Name}</th>
3434
<th class="pane-header" style="width:4em">${%Duration}</th>
3535
<th class="pane-header" style="width:3em">${%Age}</th>
36+
<j:forEach var="tableheader" items="${it.testActions}">
37+
<st:include it="${tableheader}" page="casetableheader.jelly" optional="true"/>
38+
</j:forEach>
3639
</tr>
3740
</thead>
3841
<j:forEach var="f" items="${it.failedTests}" varStatus="i">
@@ -44,6 +47,9 @@ THE SOFTWARE.
4447
<td class="pane" style="text-align:right;">
4548
<a href="${rootURL}/${f.failedSinceRun.url}">${f.age}</a>
4649
</td>
50+
<j:forEach var="tablerow" items="${f.testActions}">
51+
<st:include it="${tablerow}" page="tablerow.jelly" optional="true"/>
52+
</j:forEach>
4753
</tr>
4854
</j:forEach>
4955
</table>
@@ -64,6 +70,9 @@ THE SOFTWARE.
6470
<th class="pane-header" style="width:3em; text-align:right; white-space:nowrap;">(${%diff})</th>
6571
<th class="pane-header" style="width:5em; text-align:right">${%Total}</th>
6672
<th class="pane-header" style="width:3em; text-align:right; white-space:nowrap;">(${%diff})</th>
73+
<j:forEach var="tableheader" items="${it.testActions}">
74+
<st:include it="${tableheader}" page="${it.childType}tableheader.jelly" optional="true"/>
75+
</j:forEach>
6776
</tr>
6877
</thead>
6978
<tbody>
@@ -94,6 +103,9 @@ THE SOFTWARE.
94103
<td class="pane" style="text-align:right" data="${p.totalCount-prev.totalCount}">
95104
${h.getDiffString2(p.totalCount-prev.totalCount)}
96105
</td>
106+
<j:forEach var="tablerow" items="${p.testActions}">
107+
<st:include it="${tablerow}" page="tablerow.jelly" optional="true"/>
108+
</j:forEach>
97109
</tr>
98110
</j:forEach>
99111
</tbody>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package hudson.tasks.junit;
2+
3+
import com.gargoylesoftware.htmlunit.html.HtmlPage;
4+
import com.gargoylesoftware.htmlunit.html.HtmlTable;
5+
import com.gargoylesoftware.htmlunit.html.HtmlTableCell;
6+
import hudson.Launcher;
7+
import hudson.model.AbstractBuild;
8+
import hudson.model.BuildListener;
9+
import hudson.model.FreeStyleBuild;
10+
import hudson.model.FreeStyleProject;
11+
import hudson.model.Result;
12+
import hudson.tasks.junit.rot13.Rot13Publisher;
13+
import hudson.tasks.test.helper.WebClientFactory;
14+
import org.apache.commons.lang3.tuple.Pair;
15+
import org.hamcrest.CoreMatchers;
16+
import org.junit.Before;
17+
import org.junit.Rule;
18+
import org.junit.Test;
19+
import org.jvnet.hudson.test.JenkinsRule;
20+
import org.jvnet.hudson.test.TestBuilder;
21+
22+
import java.io.IOException;
23+
import java.util.Collections;
24+
import java.util.List;
25+
import java.util.concurrent.TimeUnit;
26+
27+
import static org.hamcrest.MatcherAssert.assertThat;
28+
import static org.junit.Assert.assertEquals;
29+
30+
/**
31+
* Verifies that TestDataPublishers can contribute custom columns to html tables in result pages.
32+
*/
33+
public class CustomColumnsTest {
34+
35+
@Rule
36+
public JenkinsRule jenkins = new JenkinsRule();
37+
38+
private FreeStyleProject project;
39+
40+
private static final String reportFileName = "junit-report-494.xml";
41+
42+
@Before
43+
public void setUp() throws Exception {
44+
project = jenkins.createFreeStyleProject("customcolumns");
45+
JUnitResultArchiver archiver = new JUnitResultArchiver("*.xml");
46+
archiver.setTestDataPublishers(Collections.singletonList(new Rot13Publisher()));
47+
archiver.setSkipPublishingChecks(true);
48+
project.getPublishersList().add(archiver);
49+
project.getBuildersList().add(new TestBuilder() {
50+
@Override
51+
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
52+
throws InterruptedException, IOException {
53+
build.getWorkspace().child(reportFileName).copyFrom(getClass().getResource(reportFileName));
54+
return true;
55+
}
56+
});
57+
FreeStyleBuild build = project.scheduleBuild2(0).get(5, TimeUnit.MINUTES);
58+
jenkins.assertBuildStatus(Result.UNSTABLE, build);
59+
}
60+
61+
@SafeVarargs
62+
private void verifyThatTableContainsExpectedValues(String pathToPage, String tableId, String headerName,
63+
Pair<String, String>... rowValues) throws Exception {
64+
65+
JenkinsRule.WebClient wc = WebClientFactory.createWebClientWithDisabledJavaScript(jenkins);
66+
HtmlPage projectPage = wc.getPage(project);
67+
jenkins.assertGoodStatus(projectPage);
68+
HtmlPage classReportPage = wc.getPage(project, pathToPage);
69+
jenkins.assertGoodStatus(classReportPage);
70+
71+
HtmlTable testResultTable = (HtmlTable) classReportPage.getFirstByXPath("//table[@id='" + tableId + "']");
72+
List<HtmlTableCell> headerRowCells = testResultTable.getHeader().getRows().get(0).getCells();
73+
int numberOfColumns = headerRowCells.size();
74+
assertEquals(headerName, headerRowCells.get(numberOfColumns - 1).asNormalizedText());
75+
76+
for (int x = 0; x < rowValues.length; x++) {
77+
List<HtmlTableCell> bodyRowCells = testResultTable.getBodies().get(0).getRows().get(x).getCells();
78+
assertThat(bodyRowCells.get(0).asNormalizedText(), CoreMatchers.containsString(rowValues[x].getLeft()));
79+
assertEquals(rowValues[x].getRight(), bodyRowCells.get(numberOfColumns - 1).asNormalizedText());
80+
}
81+
}
82+
83+
@Test
84+
public void verifyThatCustomColumnIsAddedToTheTestsTableOnTheClassResultPage() throws Exception {
85+
verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/AnExampleTestClass/",
86+
"testresult", "ROT13 for cases on class page", Pair.of("testCaseA", "grfgPnfrN for case"), Pair.of(
87+
"testCaseZ", "grfgPnfrM for case"));
88+
}
89+
90+
@Test
91+
public void verifyThatCustomColumnIsAddedToTheFailedTestsTableOnThePackageResultPage() throws Exception {
92+
verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/", "failedtestresult",
93+
"ROT13 for failed cases on package page", Pair.of("testCaseA", "grfgPnfrN for case"));
94+
}
95+
96+
@Test
97+
public void verifyThatCustomColumnIsAddedToTheClassesTableOnThePackageResultPage() throws Exception {
98+
verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/", "testresult",
99+
"ROT13 for all classes on package page", Pair.of("AnExampleTestClass", "NaRknzcyrGrfgPynff for class"));
100+
}
101+
102+
@Test
103+
public void verifyThatCustomColumnIsAddedToTheFailedTestsTableOnTheTestResultPage() throws Exception {
104+
verifyThatTableContainsExpectedValues("/lastBuild/testReport/", "failedtestresult",
105+
"ROT13 for failed cases on test page", Pair.of("testCaseA", "grfgPnfrN for case"));
106+
}
107+
108+
@Test
109+
public void verifyThatCustomColumnIsAddedToTheClassesTableOnTheTestResultPage() throws Exception {
110+
verifyThatTableContainsExpectedValues("/lastBuild/testReport/", "testresult",
111+
"ROT13 for all packages on test page", Pair.of("io.jenkins.example", "vb.wraxvaf.rknzcyr for package"));
112+
}
113+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package hudson.tasks.junit.rot13;
2+
3+
public class Rot13CaseAction extends Rot13CipherAction {
4+
5+
public Rot13CaseAction(String ciphertext) {
6+
super(ciphertext);
7+
}
8+
9+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package hudson.tasks.junit.rot13;
2+
3+
import hudson.tasks.junit.TestAction;
4+
5+
public abstract class Rot13CipherAction extends TestAction {
6+
7+
private final String ciphertext;
8+
9+
public Rot13CipherAction(String ciphertext) {
10+
this.ciphertext = ciphertext;
11+
}
12+
13+
@Override
14+
public final String getIconFileName() {
15+
return null;
16+
}
17+
18+
@Override
19+
public final String getDisplayName() {
20+
return null;
21+
}
22+
23+
@Override
24+
public String getUrlName() {
25+
return null;
26+
}
27+
28+
public String getCiphertext() {
29+
return ciphertext;
30+
}
31+
32+
}

0 commit comments

Comments
 (0)