Skip to content

Commit c044bba

Browse files
committed
Use java script
1 parent 1f3708d commit c044bba

3 files changed

Lines changed: 57 additions & 55 deletions

File tree

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import org.w3c.dom.Element;
2+
import javax.xml.parsers.DocumentBuilderFactory;
3+
import javax.xml.transform.OutputKeys;
4+
import javax.xml.transform.TransformerFactory;
5+
import javax.xml.transform.dom.DOMSource;
6+
import javax.xml.transform.stream.StreamResult;
7+
import java.io.File;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
/**
12+
* Tags intermediate initializationError retries with dd_tags[test.final_status]=skip.
13+
*
14+
* <p>Gradle generates synthetic "initializationError" testcases in JUnit reports for setup methods.
15+
* When a setup is retried and eventually succeeds, multiple testcases are created, with only the
16+
* last one passing. All intermediate attempts are marked skip so Test Optimization is not misled.
17+
*
18+
* <p>Usage (JEP 330): java TagInitializationErrors.java <xml-file>
19+
*/
20+
class TagInitializationErrors {
21+
public static void main(String[] args) throws Exception {
22+
if (args.length == 0) {
23+
System.err.println("Usage: java TagInitializationErrors.java <xml-file>");
24+
System.exit(1);
25+
}
26+
var xmlFile = new File(args[0]);
27+
if (!xmlFile.exists()) {
28+
System.err.println("File not found: " + xmlFile);
29+
System.exit(1);
30+
}
31+
var doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile);
32+
var testcases = doc.getElementsByTagName("testcase");
33+
List<Element> initErrorCases = new ArrayList<>();
34+
for (int i = 0; i < testcases.getLength(); i++) {
35+
var e = (Element) testcases.item(i);
36+
if ("initializationError".equals(e.getAttribute("name"))) {
37+
initErrorCases.add(e);
38+
}
39+
}
40+
if (initErrorCases.size() <= 1) return;
41+
for (int i = 0; i < initErrorCases.size() - 1; i++) {
42+
var testcase = initErrorCases.get(i);
43+
var properties = doc.createElement("properties");
44+
var property = doc.createElement("property");
45+
property.setAttribute("name", "dd_tags[test.final_status]");
46+
property.setAttribute("value", "skip");
47+
properties.appendChild(property);
48+
testcase.appendChild(properties);
49+
}
50+
var transformer = TransformerFactory.newInstance().newTransformer();
51+
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
52+
transformer.transform(new DOMSource(doc), new StreamResult(xmlFile));
53+
}
54+
}

.gitlab/collect_results.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ do
9090
echo " (non-stable test names detected)"
9191
fi
9292

93+
echo "Add dd_tags[test.final_status] property on retried synthetics testcase initializationErrors"
94+
java "$(dirname "$0")/TagInitializationErrors.java" "$TARGET_DIR/$AGGREGATED_FILE_NAME"
95+
9396
echo "Add dd_tags[test.final_status] property to each testcase on $TARGET_DIR/$AGGREGATED_FILE_NAME"
9497
xsl_file="$(dirname "$0")/add_final_status.xsl"
9598
tmp_file="$(mktemp)"

buildSrc/src/main/kotlin/dd-trace-java.configure-tests.gradle.kts

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ import org.gradle.kotlin.dsl.withType
99
import org.gradle.testing.base.TestingExtension
1010
import java.time.Duration
1111
import java.time.temporal.ChronoUnit
12-
import javax.xml.parsers.DocumentBuilderFactory
13-
import javax.xml.transform.OutputKeys
14-
import javax.xml.transform.TransformerFactory
15-
import javax.xml.transform.dom.DOMSource
16-
import javax.xml.transform.stream.StreamResult
17-
import org.w3c.dom.Element
1812

1913
// Need concrete implementation of BuildService in Kotlin
2014
abstract class ForkedTestLimit : BuildService<BuildServiceParameters.None>
@@ -120,52 +114,3 @@ tasks.withType<Test>().configureEach {
120114
}
121115
}
122116
}
123-
124-
tasks.withType<Test>().configureEach {
125-
126-
// Gradle generates synthetic test cases in JUnit reports for setup methods. When a setup is retried
127-
// and eventually succeeds, multiple test cases are created, with only the last one passing. Since the
128-
// retry succeeds, this does not fail the CI.
129-
//
130-
// However, all intermediate attempts are reported as failures in TestOptimization, which is misleading.
131-
//
132-
// To tackle this, we'll expose a final_status field:
133-
// - "skip" for intermediate retries
134-
// - nothing on last attempt, using the defaulting made by Test Optimization
135-
//
136-
// Charles de Beauchesne, March 2025
137-
138-
doLast("post-process-junit-xml-report") {
139-
val dir = reports.junitXml.outputLocation.get().asFile
140-
if (!dir.exists()) return@doLast
141-
dir.walkTopDown()
142-
.filter { it.isFile && it.extension == "xml" }
143-
.forEach { xmlFile ->
144-
try {
145-
tagInitializationErrors(xmlFile)
146-
} catch (e: Exception) {
147-
logger.warn("Failed to remove initializationError testcases from {}: {}", xmlFile.name, e.message)
148-
}
149-
}
150-
}
151-
}
152-
153-
fun tagInitializationErrors(xmlFile: File) {
154-
val doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile)
155-
val testcases = doc.getElementsByTagName("testcase")
156-
val initErrorCases = (0 until testcases.length)
157-
.map { testcases.item(it) as Element }
158-
.filter { it.getAttribute("name") == "initializationError" }
159-
if (initErrorCases.size <= 1) return
160-
initErrorCases.dropLast(1).forEach { testcase ->
161-
val properties = doc.createElement("properties")
162-
val property = doc.createElement("property")
163-
property.setAttribute("name", "dd_tags[test.final_status]")
164-
property.setAttribute("value", "skip")
165-
properties.appendChild(property)
166-
testcase.appendChild(properties)
167-
}
168-
val transformer = TransformerFactory.newInstance().newTransformer()
169-
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8")
170-
transformer.transform(DOMSource(doc), StreamResult(xmlFile))
171-
}

0 commit comments

Comments
 (0)