Skip to content

Commit d96239c

Browse files
committed
Add Test Console Log page to build website
1 parent 62447f3 commit d96239c

File tree

8 files changed

+157
-58
lines changed

8 files changed

+157
-58
lines changed

scripts/releng/BuildDropDataGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ void buildLogsPageData() throws IOException {
151151
JSON.Array comparatorLogs = colleFilesInDirectory(comparatorLogsDirectory, _ -> true, files);
152152
logFiles.add("comparator", comparatorLogs);
153153

154-
Path file = DIRECTORY.resolve("buildlogs/logFiles.json");
154+
Path file = DIRECTORY.resolve("buildlogs/logs.json");
155155
IO.println("Write RelEng logs data to: " + file);
156156
JSON.write(logFiles, file);
157157
}

scripts/releng/TestResultsGenerator.java

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* Hannes Wellmann - split TestResultsGenerator and CompilerSummaryGenerator
1616
*******************************************************************************/
1717

18+
import static utilities.XmlProcessorFactoryRelEng.elements;
19+
1820
import java.io.IOException;
1921
import java.nio.file.Files;
2022
import java.nio.file.Path;
@@ -33,7 +35,6 @@
3335

3436
import org.w3c.dom.Document;
3537
import org.w3c.dom.Element;
36-
import org.w3c.dom.NamedNodeMap;
3738
import org.w3c.dom.Node;
3839
import org.w3c.dom.NodeList;
3940
import org.xml.sax.SAXException;
@@ -69,14 +70,14 @@ public class TestResultsGenerator {
6970
* if the file is missing or something is wrong with the file (such as is
7071
* incomplete).
7172
*/
72-
private int countErrors(Path fileName) throws ParserConfigurationException, SAXException, IOException {
73+
private void collectErrors(Path fileName, JSON.Object test)
74+
throws ParserConfigurationException, SAXException, IOException {
7375
int errorCount = -99;
7476
// File should exists, since we are "driving" this based on file list
7577
// ... but, just in case.
7678
if (!Files.exists(fileName)) {
7779
errorCount = -1;
7880
} else {
79-
8081
if (Files.size(fileName) == 0) {
8182
errorCount = -2;
8283
} else {
@@ -93,16 +94,16 @@ private int countErrors(Path fileName) throws ParserConfigurationException, SAXE
9394
// need to
9495
// loop through each to count all errors and failures.
9596
errorCount = 0;
96-
for (int i = 0; i < elementCount; i++) {
97-
final Element element = (Element) elements.item(i);
98-
final NamedNodeMap attributes = element.getAttributes();
99-
Node aNode = attributes.getNamedItem("errors");
100-
if (aNode != null) {
101-
errorCount = errorCount + Integer.parseInt(aNode.getNodeValue());
102-
}
103-
aNode = attributes.getNamedItem("failures");
104-
errorCount = errorCount + Integer.parseInt(aNode.getNodeValue());
97+
JSON.Array suites = JSON.Array.create();
98+
for (Element element : elements(elements)) {
99+
String errorsValue = element.getAttribute("errors");
100+
String failuresValue = element.getAttribute("failures");
101+
errorCount += errorsValue.isEmpty() ? 0 : Integer.parseInt(errorsValue);
102+
errorCount += failuresValue.isEmpty() ? 0 : Integer.parseInt(failuresValue);
103+
String testSuiteFQN = element.getAttribute("package") + "." + element.getAttribute("name");
104+
suites.add(JSON.String.create(testSuiteFQN));
105105
}
106+
test.add("suites", suites);
106107
}
107108
} catch (final IOException e) {
108109
println("ERROR: IOException: " + fileName);
@@ -118,7 +119,7 @@ private int countErrors(Path fileName) throws ParserConfigurationException, SAXE
118119
}
119120
}
120121
}
121-
return errorCount;
122+
test.add("errors", JSON.Integer.create(errorCount));
122123
}
123124

124125
public static void main(String[] args) throws Exception {
@@ -160,14 +161,12 @@ private void parseJUnitTestsXml() throws Exception {
160161
for (Path junitResultsFile : allFiles) {
161162
checkIfMissingFromTestManifestFile(junitResultsFile);
162163
String filename = junitResultsFile.getFileName().toString();
163-
int errorCount = countErrors(junitResultsFile);
164-
String displayName = computeDisplayName(computeCoreName(filename));
165-
String configuration = computeConfig(filename);
166-
167164
JSON.Object test = JSON.Object.create();
168-
test.add("errors", JSON.Integer.create(errorCount));
165+
collectErrors(junitResultsFile, test);
166+
String testPluginName = computeCoreName(filename);
167+
String configuration = computeConfig(filename);
169168
JSON.Object summary = summaries.computeIfAbsent(configuration, c -> JSON.Object.create());
170-
summary.add(displayName, test);
169+
summary.add(testPluginName, test);
171170
}
172171

173172
println("DEBUG: End: Parsing XML JUnit results files");
@@ -242,15 +241,6 @@ private static String computeCoreName(String fname) {
242241
return firstUnderscorepos == -1 ? fname : fname.substring(0, firstUnderscorepos);
243242
}
244243

245-
private static final String ECLIPSE_PREFIX = "org.eclipse.";
246-
247-
private static String computeDisplayName(String name) {
248-
if (name.startsWith(ECLIPSE_PREFIX)) {
249-
return name.substring(ECLIPSE_PREFIX.length());
250-
}
251-
throw new IllegalArgumentException();
252-
}
253-
254244
private static String computeConfig(String fname) {
255245
int firstUnderscorepos = fname.indexOf('_');
256246
if (firstUnderscorepos == -1) {

scripts/releng/utilities/XmlProcessorFactoryRelEng.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@
1414
package utilities;
1515

1616
import java.io.ByteArrayInputStream;
17+
import java.util.stream.IntStream;
1718

1819
import javax.xml.parsers.DocumentBuilder;
1920
import javax.xml.parsers.DocumentBuilderFactory;
2021
import javax.xml.parsers.ParserConfigurationException;
2122

23+
import org.w3c.dom.Element;
24+
import org.w3c.dom.NodeList;
2225
import org.xml.sax.EntityResolver;
2326
import org.xml.sax.InputSource;
2427

@@ -102,4 +105,9 @@ public static synchronized DocumentBuilder createDocumentBuilderIgnoringDOCTYPE(
102105
return builder;
103106
}
104107

108+
public static Iterable<Element> elements(NodeList list) {
109+
return () -> IntStream.range(0, list.getLength()).mapToObj(list::item).filter(Element.class::isInstance)
110+
.map(Element.class::cast).iterator();
111+
}
112+
105113
}

sites/eclipse/build/buildlogs/logs.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
<head>
55
<!--TODO: set proper metadata/keywords? -->
6-
<title>RelEng Logs </title>
6+
<title>RelEng Logs</title>
77
<meta name="keywords" content="eclipse,project,plug-ins,plugins,java,ide,swt,refactoring,free java ide,tools,platform,open source,development environment,development,ide" />
88
<link rel="preconnect stylesheet" href="../../page.css" /><!-- Replaced by a refernece to a contained copy on deployment -->
99
<script src="../../page.js"></script><!-- Replaced by a refernece to a contained copy on deployment -->
@@ -39,7 +39,7 @@ <h3 id="comparator">Comparator Logs</h3>
3939

4040
<script>
4141
loadPageData('../buildproperties.json')
42-
const logFiles = fetch('logFiles.json').then(r => r.json())
42+
const logFiles = fetch('logs.json').then(r => r.json())
4343

4444
contentPostProcessor = (mainElement, build) => {
4545
document.title += ` for ${build.label}`
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<!--TODO: set proper metadata/keywords? -->
6+
<title>Test Logs</title>
7+
<meta name="keywords" content="eclipse,project,plug-ins,plugins,java,ide,swt,refactoring,free java ide,tools,platform,open source,development environment,development,ide" />
8+
<link rel="preconnect stylesheet" href="../../page.css" /><!-- Replaced by a refernece to a contained copy on deployment -->
9+
<script src="../../page.js"></script><!-- Replaced by a refernece to a contained copy on deployment -->
10+
</head>
11+
12+
<body>
13+
<div data-generate="generateDefaultBreadcrumb(this, eclipseBreadcrumbBase)">
14+
<a href="../../..">Downloads</a>
15+
<a class="data-ref" href="..">${label}</a>
16+
<span>Test Logs</span>
17+
</div>
18+
19+
<main>
20+
<h2>Test Console Logs for <span class="data-ref">${label}</span></h2>
21+
<h3 id="console">Console Logs</h3>
22+
<p>These logs contain the console output captured while running the JUnit automated tests.</p>
23+
<ul id="test-console-files" style="list-style-type:square;">
24+
</ul>
25+
<div id="test-logs-container"></div>
26+
27+
</main>
28+
29+
<script>
30+
loadPageData('../buildproperties.json')
31+
32+
contentPostProcessor = (mainElement, build) => {
33+
document.title += ` for ${build.label}`
34+
const testResultsSummaries = fetchAllTestSummaryFiles(build, '')
35+
testResultsSummaries.then(testSummaries => {
36+
const consoleLogFilesList = document.getElementById('test-console-files')
37+
const testLogFilesContainer = document.getElementById('test-logs-container')
38+
const expectedTestConfigsCount = build.expectedTests.length
39+
for (let t = 0; t < expectedTestConfigsCount; t++) {
40+
const testConfig = build.expectedTests[t]
41+
const testsSummary = testSummaries[t]
42+
const tests = Object.keys(testsSummary)
43+
if (tests.length == 0) {
44+
continue; // Test configuration not yet completed
45+
}
46+
const testConfigLong = getLongTestConfigurationName(testConfig, build)
47+
const testConsoleLogFile = `${testConfigLong}_consolelog.txt`
48+
const item = document.createElement('li')
49+
item.innerHTML = `<a href="consolelogs/${testConsoleLogFile}">${testConsoleLogFile}</a>`
50+
consoleLogFilesList.appendChild(item)
51+
52+
let testLogsList = `
53+
<h4>Individual test logs from ${testConfigLong}</h4>
54+
<ul style="list-style-type:square;">
55+
`
56+
let directorLogsList = `
57+
<h4>P2 director logs while installing tests on ${testConfigLong}</h4>
58+
<ul style="list-style-type:square;">
59+
`
60+
for (const testName of tests) {
61+
const test = testsSummary[testName]
62+
const suites = test.suites // One test-plugin may execute multiple suites
63+
if (suites) {
64+
for (const testSuiteFQN of suites) {
65+
testLogsList += `
66+
<li><a href="${testConfigLong}/${testSuiteFQN}.log">${testSuiteFQN}.log</a></li>
67+
<li><a href="${testConfigLong}/${testSuiteFQN}.log">${testSuiteFQN}.txt</a></li>
68+
`
69+
directorLogsList += `
70+
<li><a href="${testConfigLong}/directorLogs/director-${testName}.log">directorLogs_director-${testName}.log</a></li>
71+
`
72+
}
73+
}
74+
}
75+
testLogsList += '</ul>'
76+
directorLogsList += '</ul>'
77+
testLogFilesContainer.append(...toElements(testLogsList + directorLogsList))
78+
}
79+
})
80+
}
81+
82+
generate()
83+
84+
</script>
85+
</body>
86+
87+
</html>

sites/eclipse/build/tests.html

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ <h3 id="logs">Logs</h3>
2222
<ul class="data-ref">
2323
<li><a href="buildlogs/reporeports/index.html"><b>Repository Reports </b></a></li>
2424
<li><a href="buildlogs/logs.html"><b>Build and Release Engineering Logs</b></a></li>
25-
<li><a href="testresults/"><b>Test Console Logs</b></a></li> <!-- TODO: Once testresults/logs.html is implementd change this link to it -->
25+
<li><a href="testresults/logs.html"><b>Test Console Logs</b></a></li>
2626
<li><a href="apitools/analysis/html/index.html"><b>API Tools Version Verification Report</b></a>
2727
This tool verifies the versions of the plugins against Eclipse ${previousReleaseAPILabel}
2828
(Exclusions listed in <a href="https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/blob//eclipse.platform.releng.tychoeclipsebuilder/eclipse/apiexclude/exclude_list_external.txt">apiexclude/exclude_list_external.txt</a>).
@@ -39,7 +39,7 @@ <h3 id="test-results">Unit Test Results</h3>
3939
</p>
4040
<p>
4141
A negative number or "DNF" means the test "Did Not Finish" for unknown reasons and hence no results page is available.
42-
In that case, more information can sometimes be found in the <a href="testresults">console logs</a>. <!-- TODO: Once testresults/logs.html is implementd change this link to testresults/logs.html#console -->
42+
In that case, more information can sometimes be found in the <a href="testresults/logs.html#console">console logs</a>.
4343
</p>
4444
<table>
4545
<thead>
@@ -96,27 +96,20 @@ <h3>Plugins containing access errors or warnings</h3>
9696
}
9797

9898
function injectTestResultsSummaryTable(build) {
99-
const jobNamePrefix = getJenkinsTestJobNamePrefix(build)
100-
101-
const testResultsSummaries = fetchAllJSON(build.expectedTests.map(c => `testresults/${jobNamePrefix}-${c}-summary.json`))
99+
const testResultsSummaries = fetchAllTestSummaryFiles(build, 'testresults/')
102100
const testResultsTable = document.getElementById('test-results-summary')
103101
const testsHeadlineCell = document.getElementById('tests-header')
104102
const testConfigsHeadline = document.getElementById('test-configurations-headline')
105103
const expectedTestConfigsCount = build.expectedTests.length
106104
testsHeadlineCell.colSpan = expectedTestConfigsCount
107105
const expectedTestsLongNames = []
108106
for (const testConfig of build.expectedTests) {
109-
const [os, arch, javaPart] = testConfig.split('-')
110-
if (!javaPart.startsWith('java')) {
111-
throw new Error('Unexpected java version: ' + testConfig)
112-
}
113-
const javaVersion = javaPart.substring(4)
107+
const [os, ws, arch, javaVersion] = parseTestConfiguration(testConfig)
114108
const headerCell = document.createElement('th');
115-
headerCell.innerHTML = `${getOSLabel(testConfig)}<br/>${getCPUArchLabel(testConfig)}<br/>Java ${javaVersion}`
109+
headerCell.innerHTML = `${getOSLabel(os)}<br/>${getCPUArchLabel(arch)}<br/>Java ${javaVersion}`
116110
headerCell.style = 'text-align:center'
117111
testConfigsHeadline.appendChild(headerCell)
118-
const ws = getWS(os)
119-
expectedTestsLongNames.push(`${jobNamePrefix}-${testConfig}_${os}.${ws}.${arch}_${javaVersion}`)
112+
expectedTestsLongNames.push(getLongTestConfigurationName(testConfig, build))
120113
}
121114
testResultsSummaries.then(testSummaries => {
122115
const allTestNames = new Set();
@@ -128,13 +121,13 @@ <h3>Plugins containing access errors or warnings</h3>
128121
sortedTestNames.sort()
129122
for (const testName of sortedTestNames) {
130123
const testRow = testResultsTable.insertRow()
131-
insertLeanCell(testRow).innerHTML = testName
124+
insertLeanCell(testRow).innerHTML = testName.replace(/^org\.eclipse\./, '')
132125
for (let t = 0; t < expectedTestConfigsCount; t++) {
133126
const testResult = testSummaries[t][testName]
134127

135128
let cellHTML = '';
136129
if (testResult) {
137-
const filename = `org.eclipse.${testName}_${expectedTestsLongNames[t]}`
130+
const filename = `${testName}_${expectedTestsLongNames[t]}`
138131
const color = testResult.errors == 0 ? 'inherit' : 'red'
139132
cellHTML = `
140133
<a style="color:${color}" title="Detailed Unit Test Results Table" href="testresults/html/${filename}.html">(${testResult.errors})</a>

sites/eclipse/page.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,6 @@ const equinoxBreadcrumbBase = toElements(`
3939
<a href="https://eclipse.dev/equinox/">Equinox</a>
4040
`);
4141

42-
function getJenkinsTestJobsFolderURL(build) {
43-
const buildType = getBuildType(build)
44-
const testJobFolderName = buildType == 'I' ? 'AutomatedTests' : 'YBuilds'
45-
return `https://ci.eclipse.org/releng/job/${testJobFolderName}`
46-
}
47-
48-
function getJenkinsTestJobNamePrefix(build) {
49-
const buildType = getBuildType(build)
50-
return `ep${build.releaseShort.replace('.', '')}${buildType}-unit`
51-
}
52-
5342
function getBuildType(buildData) {
5443
//This might be called for stable/release builds too
5544
return buildData.identifier.startsWith('Y') ? 'Y' : 'I'
@@ -104,6 +93,38 @@ function getCPUArchLabel(name) {
10493
}
10594
}
10695

96+
function getJenkinsTestJobsFolderURL(build) {
97+
const buildType = getBuildType(build)
98+
const testJobFolderName = buildType == 'I' ? 'AutomatedTests' : 'YBuilds'
99+
return `https://ci.eclipse.org/releng/job/${testJobFolderName}`
100+
}
101+
102+
function getJenkinsTestJobNamePrefix(build) {
103+
const buildType = getBuildType(build)
104+
return `ep${build.releaseShort.replace('.', '')}${buildType}-unit`
105+
}
106+
107+
function parseTestConfiguration(testConfig) {
108+
const [os, arch, javaPart] = testConfig.split('-')
109+
if (!javaPart.startsWith('java')) {
110+
throw new Error('Unexpected java version: ' + testConfig)
111+
}
112+
const javaVersion = javaPart.substring(4)
113+
const ws = getWS(os)
114+
return [os, ws, arch, javaVersion]
115+
}
116+
117+
function getLongTestConfigurationName(testConfig, buildConfig) {
118+
const jobNamePrefix = getJenkinsTestJobNamePrefix(buildConfig)
119+
const [os, ws, arch, javaVersion] = parseTestConfiguration(testConfig)
120+
return `${jobNamePrefix}-${testConfig}_${os}.${ws}.${arch}_${javaVersion}`
121+
}
122+
123+
function fetchAllTestSummaryFiles(build, testresultsPath) {
124+
const jobNamePrefix = getJenkinsTestJobNamePrefix(build)
125+
return fetchAllJSON(build.expectedTests.map(c => `${testresultsPath}${jobNamePrefix}-${c}-summary.json`))
126+
}
127+
107128
function getPreliminaryPageData() {
108129
const identifier = getIdentifierFromSiteLocation()
109130
if (identifier) {

sites/eclipse/testDataFetch.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ curl --fail -o eclipse/overview/data.json https://download.eclipse.org/eclipse/d
3131
curl --fail -o eclipse/build/buildproperties.json "${buildDrop}/buildproperties.json"
3232
curl --fail -o eclipse/build/compilerSummary.json "${buildDrop}/compilerSummary.json"
3333
curl --fail -o eclipse/build/gitLog.json "${buildDrop}/gitLog.json"
34-
curl --fail -o eclipse/build/buildlogs/logFiles.json "${buildDrop}/buildlogs/logFiles.json"
34+
curl --fail -o eclipse/build/buildlogs/logs.json "${buildDrop}/buildlogs/logs.json"
3535

3636
# Download test results
3737
# Requires jq: https://jqlang.org/download/

0 commit comments

Comments
 (0)