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