-
Notifications
You must be signed in to change notification settings - Fork 333
Expand file tree
/
Copy pathTagInitializationErrors.java
More file actions
107 lines (105 loc) · 4.29 KB
/
TagInitializationErrors.java
File metadata and controls
107 lines (105 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/// Tags intermediate `initializationError` retries with `dd_tags[test.final_status]=skip`.
///
/// Gradle generates synthetic "initializationError" testcases in JUnit reports for setup methods.
/// When a setup is retried and eventually succeeds, multiple testcases are created, with only the
/// last one passing. All intermediate attempts are marked skip so Test Optimization is not misled.
///
/// For any suite with multiple `initializationError` test cases (when retries occurred), all entries
/// but the last one are tagged by this script with `dd_tags[test.final_status]=skip`. The last
/// entry is left unmodified, allowing **Test Optimization** to apply its default status inference based
/// on the actual outcome. Files with only one (or zero) `initializationError` test cases are left unmodified.
///
/// Before:
///
/// ```
/// <testcase name="initializationError" />
/// ```
///
/// After:
///
/// ```
/// <testcase name="initializationError">
/// <properties>
/// <property name="dd_tags[test.final_status]" value="skip" />
/// </properties>
/// </testcase>
/// ```
///
/// Usage (Java 25): `java TagInitializationErrors.java junit-report.xml`
class TagInitializationErrors {
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.err.println("Usage: java TagInitializationErrors.java <xml-file>");
System.exit(1);
}
var xmlFile = new File(args[0]);
if (!xmlFile.exists()) {
System.err.println("File not found: " + xmlFile);
System.exit(1);
}
var doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile);
var testcases = doc.getElementsByTagName("testcase");
Map<String, List<Element>> byClassname = new LinkedHashMap<>();
for (int i = 0; i < testcases.getLength(); i++) {
var e = (Element) testcases.item(i);
if ("initializationError".equals(e.getAttribute("name"))) {
byClassname.computeIfAbsent(e.getAttribute("classname"), k -> new ArrayList<>()).add(e);
}
}
boolean modified = false;
for (var group : byClassname.values()) {
if (group.size() <= 1) continue;
for (int i = 0; i < group.size() - 1; i++) {
var testcase = group.get(i);
var existingProperties = testcase.getElementsByTagName("properties");
if (existingProperties.getLength() > 0) {
var props = (Element) existingProperties.item(0);
var existingProps = props.getElementsByTagName("property");
boolean alreadyTagged = false;
for (int j = 0; j < existingProps.getLength(); j++) {
if ("dd_tags[test.final_status]".equals(((Element) existingProps.item(j)).getAttribute("name"))) {
alreadyTagged = true;
break;
}
}
if (alreadyTagged) continue;
var property = doc.createElement("property");
property.setAttribute("name", "dd_tags[test.final_status]");
property.setAttribute("value", "skip");
props.appendChild(property);
} else {
var properties = doc.createElement("properties");
var property = doc.createElement("property");
property.setAttribute("name", "dd_tags[test.final_status]");
property.setAttribute("value", "skip");
properties.appendChild(property);
testcase.appendChild(properties);
}
modified = true;
}
}
if (!modified) return;
var tmpFile = File.createTempFile("TagInitializationErrors", ".xml", xmlFile.getParentFile());
try {
var transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc), new StreamResult(tmpFile));
Files.move(tmpFile.toPath(), xmlFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
tmpFile.delete();
throw e;
}
}
}