1 package org.apache.maven.plugin.failsafe;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.plugin.MojoExecutionException;
23 import org.apache.maven.plugin.MojoFailureException;
24 import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
25 import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
26 import org.apache.maven.plugins.annotations.LifecyclePhase;
27 import org.apache.maven.plugins.annotations.Mojo;
28 import org.apache.maven.plugins.annotations.Parameter;
29 import org.apache.maven.plugins.annotations.ResolutionScope;
30 import org.apache.maven.shared.utils.StringUtils;
31 import org.apache.maven.surefire.suite.RunResult;
32
33 import javax.xml.bind.JAXBException;
34 import java.io.File;
35 import java.io.IOException;
36 import java.nio.charset.Charset;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.List;
40 import java.util.Locale;
41
42 import static org.apache.maven.plugin.failsafe.xmlsummary.FailsafeSummaryXmlUtils.writeSummary;
43 import static org.apache.maven.shared.utils.ReaderFactory.FILE_ENCODING;
44
45
46
47
48
49
50
51
52 @Mojo( name = "integration-test", requiresProject = true, requiresDependencyResolution = ResolutionScope.TEST,
53 defaultPhase = LifecyclePhase.INTEGRATION_TEST, threadSafe = true )
54 public class IntegrationTestMojo
55 extends AbstractSurefireMojo
56 {
57
58 private static final String FAILSAFE_IN_PROGRESS_CONTEXT_KEY = "failsafe-in-progress";
59
60
61
62
63
64
65 @Parameter
66 private File classesDirectory;
67
68 @Parameter( readonly = true, defaultValue = "${project.build.outputDirectory}" )
69 private File defaultClassesDirectory;
70
71
72
73
74
75
76
77 @Parameter( property = "skipITs" )
78 private boolean skipITs;
79
80
81
82
83 @Parameter( defaultValue = "${project.build.directory}/failsafe-reports" )
84 private File reportsDirectory;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 @Parameter( property = "it.test" )
107 private String test;
108
109
110
111
112 @Parameter( defaultValue = "${project.build.directory}/failsafe-reports/failsafe-summary.xml", required = true )
113 private File summaryFile;
114
115
116
117
118 @Parameter( property = "failsafe.printSummary", defaultValue = "true" )
119 private boolean printSummary;
120
121
122
123
124
125 @Parameter( property = "failsafe.reportFormat", defaultValue = "brief" )
126 private String reportFormat;
127
128
129
130
131 @Parameter( property = "failsafe.useFile", defaultValue = "true" )
132 private boolean useFile;
133
134
135
136
137
138
139
140 @Parameter( property = "it.failIfNoSpecifiedTests" )
141 private Boolean failIfNoSpecifiedTests;
142
143
144
145
146
147
148
149
150
151 @Parameter( property = "maven.failsafe.debug" )
152 private String debugForkedProcess;
153
154
155
156
157
158
159
160 @Parameter( property = "failsafe.timeout" )
161 private int forkedProcessTimeoutInSeconds;
162
163
164
165
166
167
168
169
170
171
172 @Parameter( property = "failsafe.exitTimeout", defaultValue = "30" )
173 private int forkedProcessExitTimeoutInSeconds;
174
175
176
177
178
179
180
181
182
183
184
185 @Parameter( property = "failsafe.parallel.timeout" )
186 private double parallelTestsTimeoutInSeconds;
187
188
189
190
191
192
193
194
195
196
197
198
199 @Parameter( property = "failsafe.parallel.forcedTimeout" )
200 private double parallelTestsTimeoutForcedInSeconds;
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225 @Parameter
226 private List<String> includes;
227
228
229
230
231
232
233
234
235 @Parameter( property = "failsafe.useSystemClassLoader", defaultValue = "true" )
236 private boolean useSystemClassLoader;
237
238
239
240
241
242
243
244
245
246
247
248
249 @Parameter( property = "failsafe.useManifestOnlyJar", defaultValue = "true" )
250 private boolean useManifestOnlyJar;
251
252
253
254
255 @Parameter( property = "encoding", defaultValue = "${project.reporting.outputEncoding}" )
256 private String encoding;
257
258
259
260
261
262
263
264 @Parameter( property = "failsafe.rerunFailingTestsCount", defaultValue = "0" )
265 private int rerunFailingTestsCount;
266
267
268
269
270
271
272
273
274
275
276 @Parameter( property = "failsafe.suiteXmlFiles" )
277 private File[] suiteXmlFiles;
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 @Parameter( property = "failsafe.runOrder", defaultValue = "filesystem" )
304 private String runOrder;
305
306
307
308
309
310
311
312
313 @Parameter( property = "failsafe.includesFile" )
314 private File includesFile;
315
316
317
318
319
320
321
322
323 @Parameter( property = "failsafe.excludesFile" )
324 private File excludesFile;
325
326
327
328
329
330
331
332
333
334
335
336
337 @Parameter( property = "failsafe.skipAfterFailureCount", defaultValue = "0" )
338 private int skipAfterFailureCount;
339
340
341
342
343
344
345
346
347
348
349
350 @Parameter( property = "failsafe.shutdown", defaultValue = "testset" )
351 private String shutdown;
352
353 protected int getRerunFailingTestsCount()
354 {
355 return rerunFailingTestsCount;
356 }
357
358 @SuppressWarnings( "unchecked" )
359 protected void handleSummary( RunResult summary, Exception firstForkException )
360 throws MojoExecutionException, MojoFailureException
361 {
362 File summaryFile = getSummaryFile();
363 if ( !summaryFile.getParentFile().isDirectory() )
364 {
365
366 summaryFile.getParentFile().mkdirs();
367 }
368
369 try
370 {
371 Object token = getPluginContext().get( FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
372 writeSummary( summary, summaryFile, token != null, toCharset( getEncodingOrDefault() ) );
373 }
374 catch ( IOException e )
375 {
376 throw new MojoExecutionException( e.getMessage(), e );
377 }
378 catch ( JAXBException e )
379 {
380 throw new MojoExecutionException( e.getMessage(), e );
381 }
382
383 getPluginContext().put( FAILSAFE_IN_PROGRESS_CONTEXT_KEY, FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
384 }
385
386 private String getEncodingOrDefault()
387 {
388 if ( StringUtils.isEmpty( encoding ) )
389 {
390 getConsoleLogger()
391 .warning( "File encoding has not been set, using platform encoding "
392 + FILE_ENCODING
393 + ", i.e. build is platform dependent! The file encoding for reports output files"
394 + " should be provided by the POM property ${project.reporting.outputEncoding}."
395 );
396 return FILE_ENCODING;
397 }
398 else
399 {
400 return encoding;
401 }
402 }
403
404 private boolean isJarArtifact( File artifactFile )
405 {
406 return artifactFile != null && artifactFile.isFile() && artifactFile.getName().toLowerCase().endsWith( ".jar" );
407 }
408
409 private static File toAbsoluteCanonical( File f )
410 {
411 try
412 {
413 return f == null ? null : f.getAbsoluteFile().getCanonicalFile();
414 }
415 catch ( IOException e )
416 {
417 throw new IllegalStateException( e.getLocalizedMessage(), e );
418 }
419 }
420
421 @SuppressWarnings( "deprecation" )
422 protected boolean isSkipExecution()
423 {
424 return isSkip() || isSkipTests() || isSkipITs() || isSkipExec();
425 }
426
427 protected String getPluginName()
428 {
429 return "failsafe";
430 }
431
432 protected String[] getDefaultIncludes()
433 {
434 return new String[]{ "**/IT*.java", "**/*IT.java", "**/*ITCase.java" };
435 }
436
437 @Override
438 protected String getReportSchemaLocation()
439 {
440 return "https://maven.apache.org/surefire/maven-failsafe-plugin/xsd/failsafe-test-report.xsd";
441 }
442
443 public boolean isSkipTests()
444 {
445 return skipTests;
446 }
447
448 public void setSkipTests( boolean skipTests )
449 {
450 this.skipTests = skipTests;
451 }
452
453 public boolean isSkipITs()
454 {
455 return skipITs;
456 }
457
458 public void setSkipITs( boolean skipITs )
459 {
460 this.skipITs = skipITs;
461 }
462
463 @SuppressWarnings( "deprecation" )
464 @Deprecated
465 public boolean isSkipExec()
466 {
467 return skipExec;
468 }
469
470 @SuppressWarnings( "deprecation" )
471 @Deprecated
472 public void setSkipExec( boolean skipExec )
473 {
474 this.skipExec = skipExec;
475 }
476
477 public boolean isSkip()
478 {
479 return skip;
480 }
481
482 public void setSkip( boolean skip )
483 {
484 this.skip = skip;
485 }
486
487 public File getBasedir()
488 {
489 return basedir;
490 }
491
492 public void setBasedir( File basedir )
493 {
494 this.basedir = basedir;
495 }
496
497 public File getTestClassesDirectory()
498 {
499 return testClassesDirectory;
500 }
501
502 public void setTestClassesDirectory( File testClassesDirectory )
503 {
504 this.testClassesDirectory = testClassesDirectory;
505 }
506
507
508
509
510
511
512 public File getClassesDirectory()
513 {
514 File artifact = getProject().getArtifact().getFile();
515 boolean isDefaultClsDir = classesDirectory == null;
516 return isDefaultClsDir ? ( isJarArtifact( artifact ) ? artifact : defaultClassesDirectory ) : classesDirectory;
517 }
518
519 public void setClassesDirectory( File classesDirectory )
520 {
521 this.classesDirectory = toAbsoluteCanonical( classesDirectory );
522 }
523
524 public void setDefaultClassesDirectory( File defaultClassesDirectory )
525 {
526 this.defaultClassesDirectory = toAbsoluteCanonical( defaultClassesDirectory );
527 }
528
529 public File getReportsDirectory()
530 {
531 return reportsDirectory;
532 }
533
534 public void setReportsDirectory( File reportsDirectory )
535 {
536 this.reportsDirectory = reportsDirectory;
537 }
538
539 public String getTest()
540 {
541 return test;
542 }
543
544 public void setTest( String test )
545 {
546 this.test = test;
547 }
548
549 public File getSummaryFile()
550 {
551 return summaryFile;
552 }
553
554 public void setSummaryFile( File summaryFile )
555 {
556 this.summaryFile = summaryFile;
557 }
558
559 public boolean isPrintSummary()
560 {
561 return printSummary;
562 }
563
564 public void setPrintSummary( boolean printSummary )
565 {
566 this.printSummary = printSummary;
567 }
568
569 public String getReportFormat()
570 {
571 return reportFormat;
572 }
573
574 public void setReportFormat( String reportFormat )
575 {
576 this.reportFormat = reportFormat;
577 }
578
579 public boolean isUseFile()
580 {
581 return useFile;
582 }
583
584 public void setUseFile( boolean useFile )
585 {
586 this.useFile = useFile;
587 }
588
589 public String getDebugForkedProcess()
590 {
591 return debugForkedProcess;
592 }
593
594 public void setDebugForkedProcess( String debugForkedProcess )
595 {
596 this.debugForkedProcess = debugForkedProcess;
597 }
598
599 public int getForkedProcessTimeoutInSeconds()
600 {
601 return forkedProcessTimeoutInSeconds;
602 }
603
604 public void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds )
605 {
606 this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
607 }
608
609 public int getForkedProcessExitTimeoutInSeconds()
610 {
611 return forkedProcessExitTimeoutInSeconds;
612 }
613
614 public void setForkedProcessExitTimeoutInSeconds( int forkedProcessExitTimeoutInSeconds )
615 {
616 this.forkedProcessExitTimeoutInSeconds = forkedProcessExitTimeoutInSeconds;
617 }
618
619 public double getParallelTestsTimeoutInSeconds()
620 {
621 return parallelTestsTimeoutInSeconds;
622 }
623
624 public void setParallelTestsTimeoutInSeconds( double parallelTestsTimeoutInSeconds )
625 {
626 this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds;
627 }
628
629 public double getParallelTestsTimeoutForcedInSeconds()
630 {
631 return parallelTestsTimeoutForcedInSeconds;
632 }
633
634 public void setParallelTestsTimeoutForcedInSeconds( double parallelTestsTimeoutForcedInSeconds )
635 {
636 this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds;
637 }
638
639 public boolean isUseSystemClassLoader()
640 {
641 return useSystemClassLoader;
642 }
643
644 public void setUseSystemClassLoader( boolean useSystemClassLoader )
645 {
646 this.useSystemClassLoader = useSystemClassLoader;
647 }
648
649 public boolean isUseManifestOnlyJar()
650 {
651 return useManifestOnlyJar;
652 }
653
654 public void setUseManifestOnlyJar( boolean useManifestOnlyJar )
655 {
656 this.useManifestOnlyJar = useManifestOnlyJar;
657 }
658
659
660
661 public boolean isTestFailureIgnore()
662 {
663 return true;
664 }
665
666 public void setTestFailureIgnore( boolean testFailureIgnore )
667 {
668
669 }
670
671 protected void addPluginSpecificChecksumItems( ChecksumCalculator checksum )
672 {
673 checksum.add( skipITs );
674 checksum.add( summaryFile );
675 }
676
677 public Boolean getFailIfNoSpecifiedTests()
678 {
679 return failIfNoSpecifiedTests;
680 }
681
682 public void setFailIfNoSpecifiedTests( boolean failIfNoSpecifiedTests )
683 {
684 this.failIfNoSpecifiedTests = failIfNoSpecifiedTests;
685 }
686
687 public int getSkipAfterFailureCount()
688 {
689 return skipAfterFailureCount;
690 }
691
692 public String getShutdown()
693 {
694 return shutdown;
695 }
696
697 @Override
698 public List<String> getIncludes()
699 {
700 return includes;
701 }
702
703 @Override
704 public void setIncludes( List<String> includes )
705 {
706 this.includes = includes;
707 }
708
709 public File[] getSuiteXmlFiles()
710 {
711 return suiteXmlFiles.clone();
712 }
713
714 @SuppressWarnings( "UnusedDeclaration" )
715 public void setSuiteXmlFiles( File[] suiteXmlFiles )
716 {
717 this.suiteXmlFiles = suiteXmlFiles.clone();
718 }
719
720 public String getRunOrder()
721 {
722 return runOrder;
723 }
724
725 @SuppressWarnings( "UnusedDeclaration" )
726 public void setRunOrder( String runOrder )
727 {
728 this.runOrder = runOrder;
729 }
730
731 @Override
732 public File getIncludesFile()
733 {
734 return includesFile;
735 }
736
737 @Override
738 public File getExcludesFile()
739 {
740 return excludesFile;
741 }
742
743 @Override
744 protected final List<File> suiteXmlFiles()
745 {
746 return hasSuiteXmlFiles() ? Arrays.asList( suiteXmlFiles ) : Collections.<File>emptyList();
747 }
748
749 @Override
750 protected final boolean hasSuiteXmlFiles()
751 {
752 return suiteXmlFiles != null && suiteXmlFiles.length != 0;
753 }
754
755 static Charset toCharset( String encoding )
756 {
757 return Charset.forName( Charset.isSupported( encoding ) ? encoding : encoding.toUpperCase( Locale.ROOT ) );
758 }
759 }