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