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