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.commons.io.IOUtils;
23 import org.apache.maven.surefire.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.XPathConstants;
29 import javax.xml.xpath.XPathFactory;
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.util.Locale;
35
36 import static java.lang.Boolean.parseBoolean;
37 import static java.lang.Integer.parseInt;
38 import static org.apache.commons.lang3.StringEscapeUtils.escapeXml10;
39 import static org.apache.commons.lang3.StringEscapeUtils.unescapeXml;
40 import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
41 import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
42
43
44
45
46
47 public final class FailsafeSummaryXmlUtils
48 {
49 private static final String FAILSAFE_SUMMARY_XML_SCHEMA_LOCATION =
50 "https://maven.apache.org/surefire/maven-surefire-plugin/xsd/failsafe-summary.xsd";
51
52 private static final String FAILSAFE_SUMMARY_XML_NIL_ATTR =
53 " xsi:nil=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
54
55 private static final String FAILSAFE_SUMMARY_XML_TEMPLATE =
56 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
57 + "<failsafe-summary xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
58 + " xsi:noNamespaceSchemaLocation=\"" + FAILSAFE_SUMMARY_XML_SCHEMA_LOCATION + "\""
59 + " result=\"%s\" timeout=\"%s\">\n"
60 + " <completed>%d</completed>\n"
61 + " <errors>%d</errors>\n"
62 + " <failures>%d</failures>\n"
63 + " <skipped>%d</skipped>\n"
64 + " <failureMessage%s>%s</failureMessage>\n"
65 + "</failsafe-summary>";
66
67 private FailsafeSummaryXmlUtils()
68 {
69 throw new IllegalStateException( "No instantiable constructor." );
70 }
71
72 public static RunResult toRunResult( File failsafeSummaryXml ) throws Exception
73 {
74 XPathFactory xpathFactory = XPathFactory.newInstance();
75 XPath xpath = xpathFactory.newXPath();
76
77 FileInputStream is = new FileInputStream( failsafeSummaryXml );
78
79 try
80 {
81 Node root = (Node) xpath.evaluate( "/", new InputSource( is ), XPathConstants.NODE );
82
83 String completed = xpath.evaluate( "/failsafe-summary/completed", root );
84 String errors = xpath.evaluate( "/failsafe-summary/errors", root );
85 String failures = xpath.evaluate( "/failsafe-summary/failures", root );
86 String skipped = xpath.evaluate( "/failsafe-summary/skipped", root );
87 String failureMessage = xpath.evaluate( "/failsafe-summary/failureMessage", root );
88 String timeout = xpath.evaluate( "/failsafe-summary/@timeout", root );
89
90 return new RunResult( parseInt( completed ), parseInt( errors ), parseInt( failures ), parseInt( skipped ),
91 isBlank( failureMessage ) ? null : unescapeXml( failureMessage ),
92 parseBoolean( timeout )
93 );
94 }
95 finally
96 {
97 is.close();
98 }
99 }
100
101 public static void fromRunResultToFile( RunResult fromRunResult, File toFailsafeSummaryXml )
102 throws IOException
103 {
104 String failure = fromRunResult.getFailure();
105 String xml = String.format( Locale.ROOT, FAILSAFE_SUMMARY_XML_TEMPLATE,
106 fromRunResult.getFailsafeCode(),
107 String.valueOf( fromRunResult.isTimeout() ),
108 fromRunResult.getCompletedCount(),
109 fromRunResult.getErrors(),
110 fromRunResult.getFailures(),
111 fromRunResult.getSkipped(),
112 isBlank( failure ) ? FAILSAFE_SUMMARY_XML_NIL_ATTR : "",
113 isBlank( failure ) ? "" : escapeXml10( failure )
114 );
115
116 FileOutputStream os = new FileOutputStream( toFailsafeSummaryXml );
117 try
118 {
119 IOUtils.write( xml, os, UTF_8 );
120 }
121 finally
122 {
123 os.close();
124 }
125 }
126
127 public static void writeSummary( RunResult mergedSummary, File mergedSummaryFile, boolean inProgress )
128 throws Exception
129 {
130 if ( !mergedSummaryFile.getParentFile().isDirectory() )
131 {
132
133 mergedSummaryFile.getParentFile().mkdirs();
134 }
135
136 if ( mergedSummaryFile.exists() && inProgress )
137 {
138 RunResult runResult = toRunResult( mergedSummaryFile );
139 mergedSummary = mergedSummary.aggregate( runResult );
140 }
141
142 fromRunResultToFile( mergedSummary, mergedSummaryFile );
143 }
144 }