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.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.Reader;
30 import java.util.Locale;
31
32 import org.apache.maven.surefire.api.suite.RunResult;
33 import org.apache.maven.surefire.shared.io.IOUtils;
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 String.valueOf(fromRunResult.isTimeout()),
106 fromRunResult.getCompletedCount(),
107 fromRunResult.getErrors(),
108 fromRunResult.getFailures(),
109 fromRunResult.getSkipped(),
110 msg);
111
112 try (FileOutputStream os = new FileOutputStream(toFailsafeSummaryXml)) {
113 IOUtils.write(xml, os, UTF_8);
114 }
115 }
116
117 public static void writeSummary(RunResult mergedSummary, File mergedSummaryFile, boolean inProgress)
118 throws Exception {
119 if (!mergedSummaryFile.getParentFile().isDirectory()) {
120
121 mergedSummaryFile.getParentFile().mkdirs();
122 }
123
124 if (mergedSummaryFile.exists() && inProgress) {
125 RunResult runResult = toRunResult(mergedSummaryFile);
126 mergedSummary = mergedSummary.aggregate(runResult);
127 }
128
129 fromRunResultToFile(mergedSummary, mergedSummaryFile);
130 }
131 }