View Javadoc
1   package org.apache.maven.plugins.surefire.report;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.ResourceBundle;
29  import org.apache.maven.model.ReportPlugin;
30  import org.apache.maven.plugins.annotations.Parameter;
31  import org.apache.maven.project.MavenProject;
32  import org.apache.maven.reporting.AbstractMavenReport;
33  import org.apache.maven.reporting.MavenReportException;
34  import org.apache.maven.shared.utils.PathTool;
35  import org.apache.maven.shared.utils.StringUtils;
36  
37  /**
38   * Abstract base class for reporting test results using Surefire.
39   *
40   * @author Stephen Connolly
41   */
42  public abstract class AbstractSurefireReportMojo
43      extends AbstractMavenReport
44  {
45      /**
46       * If set to false, only failures are shown.
47       *
48       * @noinspection UnusedDeclaration
49       */
50      @Parameter( defaultValue = "true", required = true, property = "showSuccess" )
51      private boolean showSuccess;
52  
53      /**
54       * Directories containing the XML Report files that will be parsed and rendered to HTML format.
55       *
56       * @noinspection UnusedDeclaration
57       */
58      @Parameter
59      private File[] reportsDirectories;
60  
61      /**
62       * (Deprecated, use reportsDirectories) This directory contains the XML Report files that will be parsed and
63       * rendered to HTML format.
64       *
65       * @noinspection UnusedDeclaration
66       */
67      @Deprecated
68      @Parameter
69      private File reportsDirectory;
70  
71      /**
72       * The projects in the reactor for aggregation report.
73       *
74       * @noinspection MismatchedQueryAndUpdateOfCollection, UnusedDeclaration
75       */
76      @Parameter( defaultValue = "${reactorProjects}", readonly = true )
77      private List<MavenProject> reactorProjects;
78  
79      /**
80       * Location of the Xrefs to link.
81       *
82       * @noinspection UnusedDeclaration
83       */
84      @Parameter( defaultValue = "${project.reporting.outputDirectory}/xref-test" )
85      private File xrefLocation;
86  
87      /**
88       * Whether to link the XRef if found.
89       *
90       * @noinspection UnusedDeclaration
91       */
92      @Parameter( defaultValue = "true", property = "linkXRef" )
93      private boolean linkXRef;
94  
95      /**
96       * Whether to build an aggregated report at the root, or build individual reports.
97       *
98       * @noinspection UnusedDeclaration
99       */
100     @Parameter( defaultValue = "false", property = "aggregate" )
101     private boolean aggregate;
102 
103     /**
104      * Whether the report should be generated or not.
105      *
106      * @return {@code true} if and only if the report should be generated.
107      * @since 2.11
108      */
109     protected boolean isSkipped()
110     {
111         return false;
112     }
113 
114     /**
115      * Whether the report should be generated when there are no test results.
116      *
117      * @return {@code true} if and only if the report should be generated when there are no result files at all.
118      * @since 2.11
119      */
120     protected boolean isGeneratedWhenNoResults()
121     {
122         return false;
123     }
124 
125     /**
126      * {@inheritDoc}
127      */
128     public void executeReport( Locale locale )
129         throws MavenReportException
130     {
131         if ( isSkipped() )
132         {
133             return;
134         }
135 
136         final List<File> reportsDirectoryList = getReportsDirectories();
137 
138         if ( reportsDirectoryList == null )
139         {
140             return;
141         }
142 
143         if ( !isGeneratedWhenNoResults() )
144         {
145             boolean atLeastOneDirectoryExists = false;
146             for ( Iterator<File> i = reportsDirectoryList.iterator(); i.hasNext() && !atLeastOneDirectoryExists; )
147             {
148                 atLeastOneDirectoryExists = SurefireReportParser.hasReportFiles( i.next() );
149             }
150             if ( !atLeastOneDirectoryExists )
151             {
152                 return;
153             }
154         }
155 
156         SurefireReportGenerator report =
157             new SurefireReportGenerator( reportsDirectoryList, locale, showSuccess, determineXrefLocation() );
158 
159         report.doGenerateReport( getBundle( locale ), getSink() );
160     }
161 
162     public boolean canGenerateReport()
163     {
164         if ( isSkipped() )
165         {
166             return false;
167         }
168 
169         final List<File> reportsDirectoryList = getReportsDirectories();
170 
171         if ( reportsDirectoryList == null )
172         {
173             return false;
174         }
175 
176         if ( !isGeneratedWhenNoResults() )
177         {
178             boolean atLeastOneDirectoryExists = false;
179             for ( Iterator<File> i = reportsDirectoryList.iterator(); i.hasNext() && !atLeastOneDirectoryExists; )
180             {
181                 atLeastOneDirectoryExists = SurefireReportParser.hasReportFiles( i.next() );
182             }
183             if ( !atLeastOneDirectoryExists )
184             {
185                 return false;
186             }
187         }
188 
189         return super.canGenerateReport();
190     }
191 
192     private List<File> getReportsDirectories()
193     {
194         final List<File> reportsDirectoryList = new ArrayList<File>();
195 
196         if ( reportsDirectories != null )
197         {
198             reportsDirectoryList.addAll( Arrays.asList( reportsDirectories ) );
199         }
200         //noinspection deprecation
201         if ( reportsDirectory != null )
202         {
203             //noinspection deprecation
204             reportsDirectoryList.add( reportsDirectory );
205         }
206         if ( aggregate )
207         {
208             if ( !project.isExecutionRoot() )
209             {
210                 return null;
211             }
212             if ( reportsDirectories == null )
213             {
214                 for ( MavenProject mavenProject : getProjectsWithoutRoot() )
215                 {
216                     reportsDirectoryList.add( getSurefireReportsDirectory( mavenProject ) );
217                 }
218             }
219             else
220             {
221                 // Multiple report directories are configured.
222                 // Let's see if those directories exist in each sub-module to fix SUREFIRE-570
223                 String parentBaseDir = getProject().getBasedir().getAbsolutePath();
224                 for ( MavenProject subProject : getProjectsWithoutRoot() )
225                 {
226                     String moduleBaseDir = subProject.getBasedir().getAbsolutePath();
227                     for ( File reportsDirectory1 : reportsDirectories )
228                     {
229                         String reportDir = reportsDirectory1.getPath();
230                         if ( reportDir.startsWith( parentBaseDir ) )
231                         {
232                             reportDir = reportDir.substring( parentBaseDir.length() );
233                         }
234                         File reportsDirectory = new File( moduleBaseDir, reportDir );
235                         if ( reportsDirectory.exists() && reportsDirectory.isDirectory() )
236                         {
237                             getLog().debug( "Adding report dir : " + moduleBaseDir + reportDir );
238                             reportsDirectoryList.add( reportsDirectory );
239                         }
240                     }
241                 }
242             }
243         }
244         else
245         {
246             if ( reportsDirectoryList.isEmpty() )
247             {
248 
249                 reportsDirectoryList.add( getSurefireReportsDirectory( project ) );
250             }
251         }
252         return reportsDirectoryList;
253     }
254 
255     /**
256      * Gets the default surefire reports directory for the specified project.
257      *
258      * @param subProject the project to query.
259      * @return the default surefire reports directory for the specified project.
260      */
261     protected abstract File getSurefireReportsDirectory( MavenProject subProject );
262 
263     private List<MavenProject> getProjectsWithoutRoot()
264     {
265         List<MavenProject> result = new ArrayList<MavenProject>();
266         for ( MavenProject subProject : reactorProjects )
267         {
268             if ( !project.equals( subProject ) )
269             {
270                 result.add( subProject );
271             }
272         }
273         return result;
274 
275     }
276 
277     private String determineXrefLocation()
278     {
279         String location = null;
280 
281         if ( linkXRef )
282         {
283             String relativePath = PathTool.getRelativePath( getOutputDirectory(), xrefLocation.getAbsolutePath() );
284             if ( StringUtils.isEmpty( relativePath ) )
285             {
286                 relativePath = ".";
287             }
288             relativePath = relativePath + "/" + xrefLocation.getName();
289             if ( xrefLocation.exists() )
290             {
291                 // XRef was already generated by manual execution of a lifecycle binding
292                 location = relativePath;
293             }
294             else
295             {
296                 // Not yet generated - check if the report is on its way
297                 for ( Object o : project.getReportPlugins() )
298                 {
299                     ReportPlugin report = (ReportPlugin) o;
300 
301                     String artifactId = report.getArtifactId();
302                     if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
303                     {
304                         location = relativePath;
305                     }
306                 }
307             }
308 
309             if ( location == null )
310             {
311                 getLog().warn( "Unable to locate Test Source XRef to link to - DISABLED" );
312             }
313         }
314         return location;
315     }
316 
317     /**
318      * {@inheritDoc}
319      */
320     public String getName( Locale locale )
321     {
322         return getBundle( locale ).getString( "report.surefire.name" );
323     }
324 
325     /**
326      * {@inheritDoc}
327      */
328     public String getDescription( Locale locale )
329     {
330         return getBundle( locale ).getString( "report.surefire.description" );
331     }
332 
333     /**
334      * {@inheritDoc}
335      */
336     public abstract String getOutputName();
337 
338     private ResourceBundle getBundle( Locale locale )
339     {
340         return ResourceBundle.getBundle( "surefire-report", locale, this.getClass().getClassLoader() );
341     }
342 }