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;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.util.Collection;
24
25 import org.apache.maven.execution.MavenSession;
26 import org.apache.maven.plugin.AbstractMojo;
27 import org.apache.maven.plugin.MojoExecutionException;
28 import org.apache.maven.plugin.MojoFailureException;
29 import org.apache.maven.plugin.failsafe.util.FailsafeSummaryXmlUtils;
30 import org.apache.maven.plugin.surefire.SurefireHelper;
31 import org.apache.maven.plugin.surefire.SurefireReportParameters;
32 import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
33 import org.apache.maven.plugins.annotations.LifecyclePhase;
34 import org.apache.maven.plugins.annotations.Mojo;
35 import org.apache.maven.plugins.annotations.Parameter;
36 import org.apache.maven.surefire.api.cli.CommandLineOption;
37 import org.apache.maven.surefire.api.suite.RunResult;
38 import org.apache.maven.surefire.booter.SurefireBooterForkException;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import static org.apache.maven.plugin.surefire.SurefireHelper.reportExecution;
43 import static org.apache.maven.surefire.api.suite.RunResult.noTestsRun;
44 import static org.apache.maven.surefire.shared.utils.StringUtils.capitalizeFirstLetter;
45
46
47
48
49
50
51
52 @SuppressWarnings("unused")
53 @Mojo(name = "verify", defaultPhase = LifecyclePhase.VERIFY, requiresProject = true, threadSafe = true)
54 public class VerifyMojo extends AbstractMojo implements SurefireReportParameters {
55
56
57
58
59
60
61
62 @Parameter(property = "skipTests")
63 private boolean skipTests;
64
65
66
67
68
69
70
71 @Parameter(property = "skipITs")
72 private boolean skipITs;
73
74
75
76
77
78
79
80 @Deprecated
81 @Parameter(property = "maven.test.skip.exec")
82 private boolean skipExec;
83
84
85
86
87
88
89 @Parameter(property = "maven.test.skip", defaultValue = "false")
90 private boolean skip;
91
92
93
94
95
96 @Parameter(property = "maven.test.failure.ignore", defaultValue = "false")
97 private boolean testFailureIgnore;
98
99
100
101
102
103 @Parameter(defaultValue = "${basedir}")
104 private File basedir;
105
106
107
108
109
110 @Parameter(defaultValue = "${project.build.testOutputDirectory}")
111 private File testClassesDirectory;
112
113
114
115
116 @Parameter(defaultValue = "${project.build.directory}/failsafe-reports")
117 private File reportsDirectory;
118
119
120
121
122 @Parameter(defaultValue = "${project.build.directory}/failsafe-reports/failsafe-summary.xml", required = true)
123 private File summaryFile;
124
125
126
127
128
129
130 @Parameter
131 private File[] summaryFiles;
132
133
134
135
136
137
138 @Parameter(property = "failIfNoTests", defaultValue = "false")
139 private boolean failIfNoTests;
140
141
142
143
144
145
146
147 @Parameter(property = "failsafe.failOnFlakeCount", defaultValue = "0")
148 private int failOnFlakeCount;
149
150
151
152
153 @Parameter(defaultValue = "${session}", readonly = true)
154 private MavenSession session;
155
156 private Logger logger = LoggerFactory.getLogger(getClass());
157
158 private Collection<CommandLineOption> cli;
159
160 private volatile PluginConsoleLogger consoleLogger = new PluginConsoleLogger(logger);
161
162 public VerifyMojo() {
163
164 }
165
166 public VerifyMojo(Logger logger) {
167 this.logger = logger;
168 }
169
170 @Override
171 public void execute() throws MojoExecutionException, MojoFailureException {
172 cli = commandLineOptions();
173 if (verifyParameters()) {
174 logDebugOrCliShowErrors(
175 capitalizeFirstLetter(getPluginName()) + " report directory: " + getReportsDirectory());
176
177 try {
178 RunResult summary = existsSummaryFile() ? readSummary(summaryFile) : noTestsRun();
179
180 if (existsSummaryFiles()) {
181 for (final File summaryFile : summaryFiles) {
182 summary = summary.aggregate(readSummary(summaryFile));
183 }
184 }
185 reportExecution(this, summary, getConsoleLogger(), getBooterForkException(summary));
186 } catch (IOException e) {
187 throw new MojoExecutionException(e.getMessage(), e);
188 }
189 }
190 }
191
192 private Exception getBooterForkException(RunResult summary) {
193 String firstForkExceptionFailureMessage = String.format("%s: ", SurefireBooterForkException.class.getName());
194 if (summary.getFailure() != null && summary.getFailure().contains(firstForkExceptionFailureMessage)) {
195 return new SurefireBooterForkException(
196 summary.getFailure().substring(firstForkExceptionFailureMessage.length()));
197 }
198 return null;
199 }
200
201 private PluginConsoleLogger getConsoleLogger() {
202 if (consoleLogger == null) {
203 synchronized (this) {
204 if (consoleLogger == null) {
205 consoleLogger = new PluginConsoleLogger(logger);
206 }
207 }
208 }
209 return consoleLogger;
210 }
211
212 private RunResult readSummary(File summaryFile) throws IOException {
213 return FailsafeSummaryXmlUtils.toRunResult(summaryFile);
214 }
215
216 protected boolean verifyParameters() throws MojoFailureException {
217 if (isSkip() || isSkipTests() || isSkipITs() || isSkipExec()) {
218 getConsoleLogger().info("Tests are skipped.");
219 return false;
220 }
221
222 if (!getTestClassesDirectory().exists()) {
223 if (getFailIfNoTests()) {
224 throw new MojoFailureException("No tests to run!");
225 }
226 }
227
228 if (!existsSummary()) {
229 getConsoleLogger().info("No tests to run.");
230 return false;
231 }
232
233 if (failOnFlakeCount < 0) {
234 throw new MojoFailureException("Parameter \"failOnFlakeCount\" should not be negative.");
235 }
236
237 return true;
238 }
239
240 protected String getPluginName() {
241 return "failsafe";
242 }
243
244 protected String[] getDefaultIncludes() {
245 return null;
246 }
247
248 @Override
249 public boolean isSkipTests() {
250 return skipTests;
251 }
252
253 @Override
254 public void setSkipTests(boolean skipTests) {
255 this.skipTests = skipTests;
256 }
257
258 public boolean isSkipITs() {
259 return skipITs;
260 }
261
262 public void setSkipITs(boolean skipITs) {
263 this.skipITs = skipITs;
264 }
265
266 @Override
267 @Deprecated
268 public boolean isSkipExec() {
269 return skipExec;
270 }
271
272 @Override
273 @Deprecated
274 public void setSkipExec(boolean skipExec) {
275 this.skipExec = skipExec;
276 }
277
278 @Override
279 public boolean isSkip() {
280 return skip;
281 }
282
283 @Override
284 public void setSkip(boolean skip) {
285 this.skip = skip;
286 }
287
288 @Override
289 public boolean isTestFailureIgnore() {
290 return testFailureIgnore;
291 }
292
293 @Override
294 public void setTestFailureIgnore(boolean testFailureIgnore) {
295 this.testFailureIgnore = testFailureIgnore;
296 }
297
298 @Override
299 public File getBasedir() {
300 return basedir;
301 }
302
303 @Override
304 public void setBasedir(File basedir) {
305 this.basedir = basedir;
306 }
307
308 @Override
309 public File getTestClassesDirectory() {
310 return testClassesDirectory;
311 }
312
313 @Override
314 public void setTestClassesDirectory(File testClassesDirectory) {
315 this.testClassesDirectory = testClassesDirectory;
316 }
317
318 @Override
319 public File getReportsDirectory() {
320 return reportsDirectory;
321 }
322
323 @Override
324 public void setReportsDirectory(File reportsDirectory) {
325 this.reportsDirectory = reportsDirectory;
326 }
327
328 public File getSummaryFile() {
329 return summaryFile;
330 }
331
332 public void setSummaryFile(File summaryFile) {
333 this.summaryFile = summaryFile;
334 }
335
336 @Override
337 public boolean getFailIfNoTests() {
338 return failIfNoTests;
339 }
340
341 @Override
342 public void setFailIfNoTests(boolean failIfNoTests) {
343 this.failIfNoTests = failIfNoTests;
344 }
345
346 @Override
347 public int getFailOnFlakeCount() {
348 return failOnFlakeCount;
349 }
350
351 @Override
352 public void setFailOnFlakeCount(int failOnFlakeCount) {
353 this.failOnFlakeCount = failOnFlakeCount;
354 }
355
356 public MavenSession getSession() {
357 return session;
358 }
359
360 public void setSession(MavenSession session) {
361 this.session = session;
362 }
363
364 private boolean existsSummaryFile() {
365 return summaryFile != null && summaryFile.isFile();
366 }
367
368 private boolean existsSummaryFiles() {
369 return summaryFiles != null && summaryFiles.length != 0;
370 }
371
372 private boolean existsSummary() {
373 return existsSummaryFile() || existsSummaryFiles();
374 }
375
376 private Collection<CommandLineOption> commandLineOptions() {
377 return SurefireHelper.commandLineOptions(session, getConsoleLogger());
378 }
379
380 private void logDebugOrCliShowErrors(String s) {
381 SurefireHelper.logDebugOrCliShowErrors(s, getConsoleLogger(), cli);
382 }
383 }