-
Notifications
You must be signed in to change notification settings - Fork 331
Tag intermediate initializationError retries with test.final_status=skip in JUnit XML
#11010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
c42a128
1f3708d
c044bba
c1bbc59
fc75f5f
42fbf91
492abbc
814275c
4af16af
899ee14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| 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.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. | ||
| * | ||
| * <p>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. | ||
| * | ||
| * <p>For any suite with multiple initializationError testcases (i.e. retries occurred), all entries | ||
| * except the last one are already tagged with an existing `dd_tags[test.final_status]`. 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 testcases are not modified. | ||
| * | ||
| * <p>Usage (JEP 330): java TagInitializationErrors.java <xml-file> | ||
| */ | ||
| 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); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❔ question: Should we add some flags about entity resolution (for example) here to prevent security issue?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which security issue do you have in mind ? The entire workflow and data are derivated from the public content of this repo, and the script itself can be modified during a PR. |
||
| 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 transformer = TransformerFactory.newInstance().newTransformer(); | ||
| transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); | ||
| transformer.transform(new DOMSource(doc), new StreamResult(xmlFile)); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 suggestion: It would help if you describe the expected changes here. You can re-use stuff from the PR description 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 899ee14