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 @Parameter
130 private File[] summaryFiles;
131
132
133
134
135
136
137 @Parameter(property = "failIfNoTests", defaultValue = "false")
138 private boolean failIfNoTests;
139
140
141
142
143
144
145
146 @Parameter(property = "failsafe.failOnFlakeCount", defaultValue = "0")
147 private int failOnFlakeCount;
148
149
150
151
152
153
154 @Deprecated
155 @Parameter(property = "encoding", defaultValue = "${project.reporting.outputEncoding}")
156 private String encoding;
157
158
159
160
161 @Parameter(defaultValue = "${session}", readonly = true)
162 private MavenSession session;
163
164 private final Logger logger;
165
166 private Collection<CommandLineOption> cli;
167
168 private volatile PluginConsoleLogger consoleLogger;
169
170 public VerifyMojo() {
171 this.logger = LoggerFactory.getLogger(getClass());
172 }
173
174 public VerifyMojo(Logger logger) {
175 this.logger = logger;
176 }
177
178 @Override
179 public void execute() throws MojoExecutionException, MojoFailureException {
180 cli = commandLineOptions();
181 if (verifyParameters()) {
182 logDebugOrCliShowErrors(
183 capitalizeFirstLetter(getPluginName()) + " report directory: " + getReportsDirectory());
184
185 try {
186 RunResult summary = existsSummaryFile() ? readSummary(summaryFile) : noTestsRun();
187
188 if (existsSummaryFiles()) {
189 for (final File summaryFile : summaryFiles) {
190 summary = summary.aggregate(readSummary(summaryFile));
191 }
192 }
193 reportExecution(this, summary, getConsoleLogger(), getBooterForkException(summary));
194 } catch (IOException e) {
195 throw new MojoExecutionException(e.getMessage(), e);
196 }
197 }
198 }
199
200 private Exception getBooterForkException(RunResult summary) {
201 String firstForkExceptionFailureMessage = String.format("%s: ", SurefireBooterForkException.class.getName());
202 if (summary.getFailure() != null && summary.getFailure().contains(firstForkExceptionFailureMessage)) {
203 return new SurefireBooterForkException(
204 summary.getFailure().substring(firstForkExceptionFailureMessage.length()));
205 }
206 return null;
207 }
208
209 private PluginConsoleLogger getConsoleLogger() {
210 if (consoleLogger == null) {
211 synchronized (this) {
212 if (consoleLogger == null) {
213 consoleLogger = new PluginConsoleLogger(logger);
214 }
215 }
216 }
217 return consoleLogger;
218 }
219
220 private RunResult readSummary(File summaryFile) throws IOException {
221 return FailsafeSummaryXmlUtils.toRunResult(summaryFile);
222 }
223
224 protected boolean verifyParameters() throws MojoFailureException {
225 if (isSkip() || isSkipTests() || isSkipITs() || isSkipExec()) {
226 getConsoleLogger().info("Tests are skipped.");
227 return false;
228 }
229
230 if (!getTestClassesDirectory().exists()) {
231 if (getFailIfNoTests()) {
232 throw new MojoFailureException("No tests to run!");
233 }
234 }
235
236 if (!existsSummary()) {
237 getConsoleLogger().info("No tests to run.");
238 return false;
239 }
240
241 if (failOnFlakeCount < 0) {
242 throw new MojoFailureException("Parameter \"failOnFlakeCount\" should not be negative.");
243 }
244
245 return true;
246 }
247
248 protected String getPluginName() {
249 return "failsafe";
250 }
251
252 protected String[] getDefaultIncludes() {
253 return null;
254 }
255
256 @Override
257 public boolean isSkipTests() {
258 return skipTests;
259 }
260
261 @Override
262 public void setSkipTests(boolean skipTests) {
263 this.skipTests = skipTests;
264 }
265
266 public boolean isSkipITs() {
267 return skipITs;
268 }
269
270 public void setSkipITs(boolean skipITs) {
271 this.skipITs = skipITs;
272 }
273
274 @Override
275 @Deprecated
276 public boolean isSkipExec() {
277 return skipExec;
278 }
279
280 @Override
281 @Deprecated
282 public void setSkipExec(boolean skipExec) {
283 this.skipExec = skipExec;
284 }
285
286 @Override
287 public boolean isSkip() {
288 return skip;
289 }
290
291 @Override
292 public void setSkip(boolean skip) {
293 this.skip = skip;
294 }
295
296 @Override
297 public boolean isTestFailureIgnore() {
298 return testFailureIgnore;
299 }
300
301 @Override
302 public void setTestFailureIgnore(boolean testFailureIgnore) {
303 this.testFailureIgnore = testFailureIgnore;
304 }
305
306 @Override
307 public File getBasedir() {
308 return basedir;
309 }
310
311 @Override
312 public void setBasedir(File basedir) {
313 this.basedir = basedir;
314 }
315
316 @Override
317 public File getTestClassesDirectory() {
318 return testClassesDirectory;
319 }
320
321 @Override
322 public void setTestClassesDirectory(File testClassesDirectory) {
323 this.testClassesDirectory = testClassesDirectory;
324 }
325
326 @Override
327 public File getReportsDirectory() {
328 return reportsDirectory;
329 }
330
331 @Override
332 public void setReportsDirectory(File reportsDirectory) {
333 this.reportsDirectory = reportsDirectory;
334 }
335
336 public File getSummaryFile() {
337 return summaryFile;
338 }
339
340 public void setSummaryFile(File summaryFile) {
341 this.summaryFile = summaryFile;
342 }
343
344 @Override
345 public boolean getFailIfNoTests() {
346 return failIfNoTests;
347 }
348
349 @Override
350 public void setFailIfNoTests(boolean failIfNoTests) {
351 this.failIfNoTests = failIfNoTests;
352 }
353
354 @Override
355 public int getFailOnFlakeCount() {
356 return failOnFlakeCount;
357 }
358
359 @Override
360 public void setFailOnFlakeCount(int failOnFlakeCount) {
361 this.failOnFlakeCount = failOnFlakeCount;
362 }
363
364 public MavenSession getSession() {
365 return session;
366 }
367
368 public void setSession(MavenSession session) {
369 this.session = session;
370 }
371
372 private boolean existsSummaryFile() {
373 return summaryFile != null && summaryFile.isFile();
374 }
375
376 private boolean existsSummaryFiles() {
377 return summaryFiles != null && summaryFiles.length != 0;
378 }
379
380 private boolean existsSummary() {
381 return existsSummaryFile() || existsSummaryFiles();
382 }
383
384 private Collection<CommandLineOption> commandLineOptions() {
385 return SurefireHelper.commandLineOptions(session, getConsoleLogger());
386 }
387
388 private void logDebugOrCliShowErrors(String s) {
389 SurefireHelper.logDebugOrCliShowErrors(s, getConsoleLogger(), cli);
390 }
391 }