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.doxia.siterenderer.Renderer;
30  import org.apache.maven.model.ReportPlugin;
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       * Location where generated html will be created.
47       *
48       * @parameter expression="${project.reporting.outputDirectory}"
49       * @noinspection UnusedDeclaration
50       */
51      private File outputDirectory;
52  
53      /**
54       * Doxia Site Renderer
55       *
56       * @component
57       * @noinspection UnusedDeclaration
58       */
59      private Renderer siteRenderer;
60  
61      /**
62       * Maven Project
63       *
64       * @parameter expression="${project}"
65       * @required @readonly
66       * @noinspection UnusedDeclaration
67       */
68      private MavenProject project;
69  
70      /**
71       * If set to false, only failures are shown.
72       *
73       * @parameter expression="${showSuccess}" default-value="true"
74       * @required
75       * @noinspection UnusedDeclaration
76       */
77      private boolean showSuccess;
78  
79      /**
80       * Directories containing the XML Report files that will be parsed and rendered to HTML format.
81       *
82       * @parameter
83       * @noinspection UnusedDeclaration
84       */
85      private File[] reportsDirectories;
86  
87      /**
88       * (Deprecated, use reportsDirectories) This directory contains the XML Report files that will be parsed and rendered to HTML format.
89       *
90       * @parameter
91       * @noinspection UnusedDeclaration
92       * @deprecated
93       */
94      private File reportsDirectory;
95  
96      /**
97       * The projects in the reactor for aggregation report.
98       *
99       * @parameter expression="${reactorProjects}"
100      * @readonly
101      * @noinspection MismatchedQueryAndUpdateOfCollection, UnusedDeclaration
102      */
103     private List<MavenProject> reactorProjects;
104 
105     /**
106      * Location of the Xrefs to link.
107      *
108      * @parameter default-value="${project.reporting.outputDirectory}/xref-test"
109      * @noinspection UnusedDeclaration
110      */
111     private File xrefLocation;
112 
113     /**
114      * Whether to link the XRef if found.
115      *
116      * @parameter expression="${linkXRef}" default-value="true"
117      * @noinspection UnusedDeclaration
118      */
119     private boolean linkXRef;
120 
121     /**
122      * Whether to build an aggregated report at the root, or build individual reports.
123      *
124      * @parameter expression="${aggregate}" default-value="false"
125      * @noinspection UnusedDeclaration
126      */
127     private boolean aggregate;
128 
129     /**
130      * Whether the report should be generated or not.
131      *
132      * @return {@code true} if and only if the report should be generated.
133      * @since 2.11
134      */
135     protected boolean isSkipped()
136     {
137         return false;
138     }
139 
140     /**
141      * Whether the report should be generated when there are no test results.
142      *
143      * @return {@code true} if and only if the report should be generated when there are no result files at all.
144      * @since 2.11
145      */
146     protected boolean isGeneratedWhenNoResults()
147     {
148         return false;
149     }
150 
151     /**
152      * {@inheritDoc}
153      */
154     public void executeReport( Locale locale )
155         throws MavenReportException
156     {
157         if ( isSkipped() )
158         {
159             return;
160         }
161 
162         final List<File> reportsDirectoryList = getReportsDirectories();
163 
164         if ( reportsDirectoryList == null )
165         {
166             return;
167         }
168 
169         if ( !isGeneratedWhenNoResults() )
170         {
171             boolean atLeastOneDirectoryExists = false;
172             for ( Iterator<File> i = reportsDirectoryList.iterator(); i.hasNext() && !atLeastOneDirectoryExists; )
173             {
174                 atLeastOneDirectoryExists = SurefireReportParser.hasReportFiles( i.next() );
175             }
176             if ( !atLeastOneDirectoryExists )
177             {
178                 return;
179             }
180         }
181 
182         SurefireReportGenerator report =
183             new SurefireReportGenerator( reportsDirectoryList, locale, showSuccess, determineXrefLocation() );
184 
185         report.doGenerateReport( getBundle( locale ), getSink() );
186     }
187 
188     public boolean canGenerateReport()
189     {
190         if ( isSkipped() )
191         {
192             return false;
193         }
194 
195         final List<File> reportsDirectoryList = getReportsDirectories();
196 
197         if ( reportsDirectoryList == null )
198         {
199             return false;
200         }
201 
202         if ( !isGeneratedWhenNoResults() )
203         {
204             boolean atLeastOneDirectoryExists = false;
205             for ( Iterator<File> i = reportsDirectoryList.iterator(); i.hasNext() && !atLeastOneDirectoryExists; )
206             {
207                 atLeastOneDirectoryExists = SurefireReportParser.hasReportFiles( i.next() );
208             }
209             if ( !atLeastOneDirectoryExists )
210             {
211                 return false;
212             }
213         }
214 
215         return super.canGenerateReport();
216     }
217 
218     private List<File> getReportsDirectories()
219     {
220         final List<File> reportsDirectoryList = new ArrayList<File>();
221 
222         if ( reportsDirectories != null )
223         {
224             reportsDirectoryList.addAll( Arrays.asList( reportsDirectories ) );
225         }
226         //noinspection deprecation
227         if ( reportsDirectory != null )
228         {
229             //noinspection deprecation
230             reportsDirectoryList.add( reportsDirectory );
231         }
232         if ( aggregate )
233         {
234             if ( !project.isExecutionRoot() )
235             {
236                 return null;
237             }
238             if ( reportsDirectories == null )
239             {
240                 for ( MavenProject mavenProject : getProjectsWithoutRoot() )
241                 {
242                     reportsDirectoryList.add( getSurefireReportsDirectory( mavenProject ) );
243                 }
244             }
245             else
246             {
247                 // Multiple report directories are configured.
248                 // Let's see if those directories exist in each sub-module to fix SUREFIRE-570
249                 String parentBaseDir = getProject().getBasedir().getAbsolutePath();
250                 for ( MavenProject subProject : getProjectsWithoutRoot() )
251                 {
252                     String moduleBaseDir = subProject.getBasedir().getAbsolutePath();
253                     for ( File reportsDirectory1 : reportsDirectories )
254                     {
255                         String reportDir = reportsDirectory1.getPath();
256                         if ( reportDir.startsWith( parentBaseDir ) )
257                         {
258                             reportDir = reportDir.substring( parentBaseDir.length() );
259                         }
260                         File reportsDirectory = new File( moduleBaseDir, reportDir );
261                         if ( reportsDirectory.exists() && reportsDirectory.isDirectory() )
262                         {
263                             getLog().debug( "Adding report dir : " + moduleBaseDir + reportDir );
264                             reportsDirectoryList.add( reportsDirectory );
265                         }
266                     }
267                 }
268             }
269         }
270         else
271         {
272             if ( reportsDirectoryList.size() == 0 )
273             {
274 
275                 reportsDirectoryList.add( getSurefireReportsDirectory( project ) );
276             }
277         }
278         return reportsDirectoryList;
279     }
280 
281     /**
282      * Gets the default surefire reports directory for the specified project.
283      *
284      * @param subProject the project to query.
285      * @return the default surefire reports directory for the specified project.
286      */
287     protected abstract File getSurefireReportsDirectory( MavenProject subProject );
288 
289     private List<MavenProject> getProjectsWithoutRoot()
290     {
291         List<MavenProject> result = new ArrayList<MavenProject>();
292         for ( MavenProject subProject : reactorProjects )
293         {
294             if ( !project.equals( subProject ) )
295             {
296                 result.add( subProject );
297             }
298         }
299         return result;
300 
301     }
302 
303     private String determineXrefLocation()
304     {
305         String location = null;
306 
307         if ( linkXRef )
308         {
309             String relativePath = PathTool.getRelativePath( getOutputDirectory(), xrefLocation.getAbsolutePath() );
310             if ( StringUtils.isEmpty( relativePath ) )
311             {
312                 relativePath = ".";
313             }
314             relativePath = relativePath + "/" + xrefLocation.getName();
315             if ( xrefLocation.exists() )
316             {
317                 // XRef was already generated by manual execution of a lifecycle binding
318                 location = relativePath;
319             }
320             else
321             {
322                 // Not yet generated - check if the report is on its way
323                 for ( Object o : project.getReportPlugins() )
324                 {
325                     ReportPlugin report = (ReportPlugin) o;
326 
327                     String artifactId = report.getArtifactId();
328                     if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
329                     {
330                         location = relativePath;
331                     }
332                 }
333             }
334 
335             if ( location == null )
336             {
337                 getLog().warn( "Unable to locate Test Source XRef to link to - DISABLED" );
338             }
339         }
340         return location;
341     }
342 
343     /**
344      * {@inheritDoc}
345      */
346     public String getName( Locale locale )
347     {
348         return getBundle( locale ).getString( "report.surefire.name" );
349     }
350 
351     /**
352      * {@inheritDoc}
353      */
354     public String getDescription( Locale locale )
355     {
356         return getBundle( locale ).getString( "report.surefire.description" );
357     }
358 
359     /**
360      * {@inheritDoc}
361      */
362     protected Renderer getSiteRenderer()
363     {
364         return siteRenderer;
365     }
366 
367     /**
368      * {@inheritDoc}
369      */
370     protected MavenProject getProject()
371     {
372         return project;
373     }
374 
375     /**
376      * {@inheritDoc}
377      */
378     public abstract String getOutputName();
379 
380     /**
381      * {@inheritDoc}
382      */
383     protected String getOutputDirectory()
384     {
385         return outputDirectory.getAbsolutePath();
386     }
387 
388     private ResourceBundle getBundle( Locale locale )
389     {
390         return ResourceBundle.getBundle( "surefire-report", locale, this.getClass().getClassLoader() );
391     }
392 }