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 + " %s\n"
68 + "</failsafe-summary>";
69
70 private FailsafeSummaryXmlUtils() {
71 throw new IllegalStateException("No instantiable constructor.");
72 }
73
74 public static RunResult toRunResult(File failsafeSummaryXml) throws Exception {
75 XPathFactory xpathFactory = XPathFactory.newInstance();
76 XPath xpath = xpathFactory.newXPath();
77
78 try (Reader reader = new InputStreamReader(new FileInputStream(failsafeSummaryXml), UTF_8)) {
79 Node root = (Node) xpath.evaluate("/", new InputSource(reader), NODE);
80
81 String completed = xpath.evaluate("/failsafe-summary/completed", root);
82 String errors = xpath.evaluate("/failsafe-summary/errors", root);
83 String failures = xpath.evaluate("/failsafe-summary/failures", root);
84 String skipped = xpath.evaluate("/failsafe-summary/skipped", root);
85 String failureMessage = xpath.evaluate("/failsafe-summary/failureMessage", root);
86 String timeout = xpath.evaluate("/failsafe-summary/@timeout", root);
87
88 return new RunResult(
89 parseInt(completed),
90 parseInt(errors),
91 parseInt(failures),
92 parseInt(skipped),
93 isBlank(failureMessage) ? null : unescapeXml(failureMessage),
94 parseBoolean(timeout));
95 }
96 }
97
98 public static void fromRunResultToFile(RunResult fromRunResult, File toFailsafeSummaryXml) throws IOException {
99 String failure = fromRunResult.getFailure();
100 String msg = isBlank(failure) ? MESSAGE_NIL_ELEMENT : format(MESSAGE_ELEMENT, escapeXml10(failure));
101 String xml = format(
102 Locale.ROOT,
103 FAILSAFE_SUMMARY_XML_TEMPLATE,
104 fromRunResult.getFailsafeCode(),
105 fromRunResult.isTimeout(),
106 fromRunResult.getCompletedCount(),
107 fromRunResult.getErrors(),
108 fromRunResult.getFailures(),
109 fromRunResult.getSkipped(),
110 msg);
111
112 Files.write(
113 toFailsafeSummaryXml.toPath(),
114 xml.getBytes(UTF_8),
115 StandardOpenOption.CREATE,
116 StandardOpenOption.TRUNCATE_EXISTING,
117 StandardOpenOption.WRITE);
118 }
119
120 public static void writeSummary(RunResult mergedSummary, File mergedSummaryFile, boolean inProgress)
121 throws Exception {
122 if (!mergedSummaryFile.getParentFile().isDirectory()) {
123
124 mergedSummaryFile.getParentFile().mkdirs();
125 }
126
127 if (mergedSummaryFile.exists() && inProgress) {
128 RunResult runResult = toRunResult(mergedSummaryFile);
129 mergedSummary = mergedSummary.aggregate(runResult);
130 }
131
132 fromRunResultToFile(mergedSummary, mergedSummaryFile);
133 }
134 }