View Javadoc
1   /*
2    * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and contributors.
3    *
4    * All rights reserved. This program and the accompanying materials
5    * are made available under the terms of the GNU Lesser General Public License
6    * (LGPL) version 2.1 which accompanies this distribution, and is available at
7    * http://www.gnu.org/licenses/lgpl-2.1.html
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * Contributors:
15   *     mguillaume, jcarsique
16   */
17  package org.nuxeo.build.maven;
18  
19  import java.io.BufferedInputStream;
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.Locale;
27  
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugin.MojoFailureException;
30  import org.apache.maven.plugin.surefire.SurefireHelper;
31  import org.apache.maven.plugin.surefire.SurefireReportParameters;
32  import org.apache.maven.plugins.annotations.LifecyclePhase;
33  import org.apache.maven.plugins.annotations.Mojo;
34  import org.apache.maven.plugins.annotations.Parameter;
35  import org.apache.maven.plugins.annotations.ResolutionScope;
36  import org.apache.maven.plugins.surefire.report.ReportTestSuite;
37  import org.apache.maven.plugins.surefire.report.SurefireReportParser;
38  import org.apache.maven.reporting.MavenReportException;
39  import org.apache.maven.surefire.suite.RunResult;
40  import org.codehaus.plexus.util.StringUtils;
41  
42  /**
43   * Read Surefire/Failsafe summary files to verify the result of integration tests. It can also read JUnit test reports,
44   * write and aggregate the results in a summary file. Typical usage is to fail the build at a different phase than the
45   * one which ran the tests, allowing environment cleanup.
46   *
47   * @see IntegrationTestMojo
48   */
49  @Mojo(name = "verify", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true, //
50  requiresProject = true, requiresDependencyResolution = ResolutionScope.TEST)
51  public class VerifyMojo extends IntegrationTestMojo implements SurefireReportParameters {
52  
53      /**
54       * Additional summary files to read integration test results from.
55       *
56       * @since 2.0
57       */
58      @Parameter
59      protected File[] summaryFiles;
60  
61      /**
62       * Option to create summary of test suites. If {@code summaryFile} already exists, the results are aggregated to the
63       * existing summary. It is also aggregating results from the {@code summaryFiles} if set.
64       *
65       * @see IntegrationTestMojo#summaryFile
66       * @see #reportsDirectory
67       * @since 2.0.5
68       */
69      @Parameter(property = "createSummary", defaultValue = "false")
70      private boolean createSummary;
71  
72      /**
73       * Base directory where the JUnit reports are read from. Only used if {@code createSummary} is true.
74       *
75       * @see #createSummary
76       * @since 2.0.5
77       */
78      @Parameter(defaultValue = "${project.build.directory}/nxtools-reports")
79      private File reportsDirectory;
80  
81      /**
82       * Set this to {@code true} to skip running tests.
83       *
84       * @since 2.0.3
85       */
86      @Parameter(property = "skipTests")
87      protected boolean skipTests;
88  
89      @Override
90      public String getEncoding() {
91          if (StringUtils.isEmpty(reportingEncoding)) {
92              reportingEncoding = super.getEncoding();
93          }
94          return reportingEncoding;
95      }
96  
97      /**
98       * Set this to true to ignore a failure during testing. Its use is NOT RECOMMENDED, but quite convenient on
99       * occasion.
100      *
101      * @since 2.0
102      */
103     @SuppressWarnings("hiding")
104     @Parameter(property = "maven.test.failure.ignore", defaultValue = "false")
105     protected boolean testFailureIgnore;
106 
107     /**
108      * Set this to "true" to cause a failure if there are no tests to run.
109      *
110      * @since 2.0
111      */
112     @Parameter(property = "failIfNoTests")
113     protected Boolean failIfNoTests;
114 
115     @Override
116     public void execute() throws MojoExecutionException, MojoFailureException {
117         if (isSkipITs() || isSkipTests()) {
118             getLog().info("Tests are skipped.");
119             return;
120         }
121 
122         RunResult summary = RunResult.noTestsRun();
123         if (createSummary) {
124             List<File> reportsDirectories = Collections.singletonList(reportsDirectory);
125             SurefireReportParser parser = new SurefireReportParser(reportsDirectories, Locale.getDefault());
126             try {
127                 List<ReportTestSuite> reports = parser.parseXMLReportFiles();
128                 if (reports.isEmpty()) {
129                     getLog().info("No report found in " + reportsDirectory);
130                 }
131                 int total = 0, errors = 0, failures = 0, skipped = 0, flakes = 0;
132                 for (ReportTestSuite report : reports) {
133                     total += report.getNumberOfTests();
134                     errors += report.getNumberOfErrors();
135                     failures += report.getNumberOfFailures();
136                     skipped += report.getNumberOfSkipped();
137                     flakes += report.getNumberOfFlakes();
138                 }
139                 summary = new RunResult(total, errors, failures, skipped, flakes);
140             } catch (MavenReportException e) {
141                 getLog().error("Could not parse reports from " + reportsDirectory, e);
142                 throw new MojoExecutionException(e.getMessage(), e);
143             }
144         }
145 
146         try {
147             if (summaryFile.isFile()) {
148                 summary = summary.aggregate(readSummary(getEncoding(), summaryFile));
149             }
150             if (summaryFiles != null) {
151                 for (File file : summaryFiles) {
152                     summary = summary.aggregate(readSummary(getEncoding(), file));
153                 }
154             }
155             if (createSummary) {
156                 writeSummary(summary);
157             }
158         } catch (IOException e) {
159             throw new MojoExecutionException(e.getMessage(), e);
160         }
161         SurefireHelper.reportExecution(this, summary, getLog());
162     }
163 
164     private RunResult readSummary(String sumEncoding, File sumFile) throws IOException {
165         try (InputStream in = new BufferedInputStream(new FileInputStream(sumFile))) {
166             return RunResult.fromInputStream(in, sumEncoding);
167         }
168     }
169 
170     /**
171      * @since 2.0.3
172      */
173     public boolean isSkipITs() {
174         return skipITs;
175     }
176 
177     /**
178      * @since 2.0.3
179      */
180     public void setSkipITs(boolean skipITs) {
181         this.skipITs = skipITs;
182     }
183 
184     @Override
185     public boolean isSkipTests() {
186         return skipTests;
187     }
188 
189     @Override
190     public void setSkipTests(boolean skipTests) {
191         this.skipTests = skipTests;
192     }
193 
194     /**
195      * @deprecated Since 2.0.3. Use {@link #isSkipITs()} or {@link #isSkipTests()}
196      */
197     @Override
198     @Deprecated
199     public boolean isSkipExec() {
200         return isSkipITs() || isSkipTests();
201     }
202 
203     /**
204      * @deprecated Since 2.0.3. Use {@link #setSkipITs(boolean)} or {@link #setSkipTests(boolean)}
205      */
206     @Override
207     @Deprecated
208     public void setSkipExec(boolean skipExec) {
209         throw new UnsupportedOperationException();
210     }
211 
212     /**
213      * @deprecated Since 2.0.3. Use {@link #isSkipITs()} or {@link #isSkipTests()}
214      */
215     @Override
216     @Deprecated
217     public boolean isSkip() {
218         return isSkipITs() || isSkipTests();
219     }
220 
221     /**
222      * @deprecated Since 2.0.3. Use {@link #setSkipITs(boolean)} or {@link #setSkipTests(boolean)}
223      */
224     @Override
225     @Deprecated
226     public void setSkip(boolean skip) {
227         throw new UnsupportedOperationException();
228     }
229 
230     @Override
231     public boolean isTestFailureIgnore() {
232         return testFailureIgnore;
233     }
234 
235     @Override
236     public void setTestFailureIgnore(boolean testFailureIgnore) {
237         this.testFailureIgnore = testFailureIgnore;
238     }
239 
240     @Override
241     public File getBasedir() {
242         return project.getBasedir();
243     }
244 
245     @Override
246     public void setBasedir(File basedir) {
247         throw new UnsupportedOperationException();
248     }
249 
250     @Override
251     public File getTestClassesDirectory() {
252         return new File(project.getBuild().getTestOutputDirectory());
253     }
254 
255     @Override
256     public void setTestClassesDirectory(File testClassesDirectory) {
257         throw new UnsupportedOperationException();
258     }
259 
260     @Override
261     public File getReportsDirectory() {
262         return summaryFile.getParentFile();
263     }
264 
265     @Override
266     public void setReportsDirectory(File reportsDirectory) {
267         throw new UnsupportedOperationException();
268     }
269 
270     @Override
271     public Boolean getFailIfNoTests() {
272         return failIfNoTests;
273     }
274 
275     @Override
276     public void setFailIfNoTests(boolean failIfNoTests) {
277         throw new UnsupportedOperationException();
278     }
279 
280 }