1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.failsafe.util;
20
21 import javax.xml.xpath.XPath;
22 import javax.xml.xpath.XPathFactory;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.io.InputStreamReader;
28 import java.io.Reader;
29 import java.nio.file.Files;
30 import java.nio.file.StandardOpenOption;
31 import java.util.Locale;
32
33 import org.apache.maven.surefire.api.suite.RunResult;
34 import org.w3c.dom.Node;
35 import org.xml.sax.InputSource;
36
37 import static java.lang.Boolean.parseBoolean;
38 import static java.lang.Integer.parseInt;
39 import static java.lang.String.format;
40 import static java.nio.charset.StandardCharsets.UTF_8;
41 import static javax.xml.xpath.XPathConstants.NODE;
42 import static org.apache.maven.surefire.shared.lang3.StringEscapeUtils.escapeXml10;
43 import static org.apache.maven.surefire.shared.lang3.StringEscapeUtils.unescapeXml;
44 import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
45
46
47
48
49
50 public final class FailsafeSummaryXmlUtils {
51 private static final String FAILSAFE_SUMMARY_XML_SCHEMA_LOCATION =
52 "https://maven.apache.org/surefire/maven-surefire-plugin/xsd/failsafe-summary.xsd";
53
54 private static final String MESSAGE_NIL_ELEMENT =
55 "<failureMessage xsi:nil=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
56
57 private static final String MESSAGE_ELEMENT = "<failureMessage>%s</failureMessage>";
58
59 private static final String FAILSAFE_SUMMARY_XML_TEMPLATE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
60 + "<failsafe-summary xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
61 + " xsi:noNamespaceSchemaLocation=\"" + FAILSAFE_SUMMARY_XML_SCHEMA_LOCATION + "\""
62 + " result=\"%s\" timeout=\"%s\">\n"
63 + " <completed>%d</completed>\n"
64 + " <errors>%d</errors>\n"
65 + " <failures>%d</failures>\n"
66 + " <skipped>%d</skipped>\n"
67 + " <flakes>%d</flakes>\n"
68 + " %s\n"
69 + "</failsafe-summary>";
70
71 private FailsafeSummaryXmlUtils() {
72 throw new IllegalStateException("No instantiable constructor.");
73 }
74
75 public static RunResult toRunResult(File failsafeSummaryXml) throws Exception {
76 XPathFactory xpathFactory = XPathFactory.newInstance();
77 XPath xpath = xpathFactory.newXPath();
78
79 try (Reader reader = new InputStreamReader(new FileInputStream(failsafeSummaryXml), UTF_8)) {
80 Node root = (Node) xpath.evaluate("/", new InputSource(reader), NODE);
81
82 String completed = xpath.evaluate("/failsafe-summary/completed", root);
83 String errors = xpath.evaluate("/failsafe-summary/errors", root);
84 String failures = xpath.evaluate("/failsafe-summary/failures", root);
85 String skipped = xpath.evaluate("/failsafe-summary/skipped", root);
86 String failureMessage = xpath.evaluate("/failsafe-summary/failureMessage", root);
87 String timeout = xpath.evaluate("/failsafe-summary/@timeout", root);
88 String flakes = xpath.evaluate("/failsafe-summary/flakes", root);
89
90 return new RunResult(
91 parseInt(completed),
92 parseInt(errors),
93 parseInt(failures),
94 parseInt(skipped),
95
96
97 isBlank(flakes) ? 0 : parseInt(flakes),
98 isBlank(failureMessage) ? null : unescapeXml(failureMessage),
99 parseBoolean(timeout));
100 }
101 }
102
103 public static void fromRunResultToFile(RunResult fromRunResult, File toFailsafeSummaryXml) throws IOException {
104 String failure = fromRunResult.getFailure();
105 String msg = isBlank(failure) ? MESSAGE_NIL_ELEMENT : format(MESSAGE_ELEMENT, escapeXml10(failure));
106 String xml = format(
107 Locale.ROOT,
108 FAILSAFE_SUMMARY_XML_TEMPLATE,
109 fromRunResult.getFailsafeCode(),
110 fromRunResult.isTimeout(),
111 fromRunResult.getCompletedCount(),
112 fromRunResult.getErrors(),
113 fromRunResult.getFailures(),
114 fromRunResult.getSkipped(),
115 fromRunResult.getFlakes(),
116 msg);
117
118 Files.write(
119 toFailsafeSummaryXml.toPath(),
120 xml.getBytes(UTF_8),
121 StandardOpenOption.CREATE,
122 StandardOpenOption.TRUNCATE_EXISTING,
123 StandardOpenOption.WRITE);
124 }
125
126 public static void writeSummary(RunResult mergedSummary, File mergedSummaryFile, boolean inProgress)
127 throws Exception {
128 if (!mergedSummaryFile.getParentFile().isDirectory()) {
129
130 mergedSummaryFile.getParentFile().mkdirs();
131 }
132
133 if (mergedSummaryFile.exists() && inProgress) {
134 RunResult runResult = toRunResult(mergedSummaryFile);
135 mergedSummary = mergedSummary.aggregate(runResult);
136 }
137
138 fromRunResultToFile(mergedSummary, mergedSummaryFile);
139 }
140 }