View Javadoc

1   package org.codehaus.mojo.fitnesse;
2   
3   /*
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU General Public License as published by
6    * the Free Software Foundation, version 2.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU General Public License for more details.
12   *
13   * You should have received a copy of the GNU General Public License
14   * along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
15   */
16  
17  import java.io.ByteArrayInputStream;
18  import java.io.ByteArrayOutputStream;
19  import java.io.File;
20  import java.io.FileOutputStream;
21  import java.io.FileWriter;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  
26  import org.apache.commons.httpclient.Credentials;
27  import org.apache.commons.httpclient.HttpClient;
28  import org.apache.commons.httpclient.HttpMethod;
29  import org.apache.commons.httpclient.auth.AuthScope;
30  import org.apache.commons.httpclient.methods.GetMethod;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.apache.maven.reporting.MavenReportException;
34  
35  /**
36   * This goal uses the <code>fitnesse.runner.TestRunner</code> class for calling a remote FitNesse web page and
37   * executes the <i>tests</i> or <i>suites</i> locally into a forked JVM. It's possible to define several pages and/or
38   * servers.
39   * 
40   * @goal remotecall
41   * @aggregator
42   */
43  public class FitnesseRemoteRunnerMojo
44      extends FitnesseAbstractMojo
45  {
46  
47      public static final String START_REPORT_TAG_KO = "document.getElementById(\"test-summary\").className = \"fail\"";
48  
49      public static final String START_REPORT_TAG_KO2 = "document.getElementById(\"test-summary\").className = \"error\"";
50  
51      public static final String START_REPORT_TAG_OK = "document.getElementById(\"test-summary\").className = \"pass\"";
52  
53      public void execute()
54          throws MojoExecutionException, MojoFailureException
55      {
56          new File( this.workingDir ).mkdirs();
57          checkConfiguration();
58  
59          try
60          {
61              FitnesseReportMojo.copyAllResources( new File( this.workingDir ), getLog(), getClass().getClassLoader() );
62          }
63          catch ( MavenReportException e )
64          {
65              throw new MojoExecutionException( "Unable to copy resources", e.getCause() );
66          }
67  
68          getLog().info( "Found " + getFitnesseSize() + " Fitnesse configuration." );
69          MojoFailureException tLastFailure = null;
70          for ( int i = 0; i < getFitnesseSize(); i++ )
71          {
72              try
73              {
74                  callFitnesse( i );
75              }
76              catch ( MojoFailureException e )
77              {
78                  tLastFailure = e;
79              }
80          }
81          if ( tLastFailure != null )
82          {
83              throw tLastFailure;
84          }
85      }
86  
87      /**
88       * Call a Fitnesse server page.
89       * 
90       * @param pServerConfPosition The number of the Fitnesse configuration.
91       * @throws MojoFailureException
92       * @throws MojoExecutionException
93       */
94      void callFitnesse( int pServerConfPosition )
95          throws MojoFailureException, MojoExecutionException
96      {
97          Fitnesse tServer = getFitnesse( pServerConfPosition );
98  
99          File tResultFile = new File( this.getFinalFileName( tServer ) );
100         if ( tResultFile.exists() )
101         {
102             tResultFile.delete();
103         }
104         File tOutput = new File( this.getOutputFileName( tServer ) );
105         if ( tOutput.exists() )
106         {
107             tOutput.delete();
108         }
109         try
110         {
111             FileOutputStream tOutputStream = new FileOutputStream( tOutput );
112 
113             tResultFile.createNewFile();
114             ByteArrayOutputStream tOut = new ByteArrayOutputStream();
115             getRemoteResource( "http://" + tServer.getHostName() + ":" + tServer.getPort() + "/"
116                 + tServer.getPageName() + "?" + tServer.getType(), tOut, tServer );
117 
118             String tOutAsString = tOut.toString();
119             FitnessePage tFitnessePage = new FitnessePage( tOutAsString );
120             transformHtml( new ByteArrayInputStream( tOut.toByteArray() ), new FileWriter( tResultFile ),
121                            getOutputUrl( tServer ), tFitnessePage.getStatus() );
122 
123             getRemoteResource( "http://" + tServer.getHostName() + ":" + tServer.getPort() + "/ErrorLogs."
124                 + tServer.getPageName(), tOutputStream, tServer );
125             transformOutputPage( this.getOutputFileName( tServer ) );
126 
127             checkFailure( tOutAsString, tResultFile.getAbsolutePath() );
128 
129         }
130         catch ( IOException e )
131         {
132             throw new MojoExecutionException( "Unable to create File [" + tResultFile.getAbsolutePath() + "].", e );
133         }
134 
135     }
136 
137     void transformOutputPage( String pFinalOutputName )
138         throws IOException, MojoExecutionException
139     {
140         String tSrcAsString = FileUtil.getString( new File( pFinalOutputName ) );
141         tSrcAsString = tSrcAsString.replaceAll( "/files/css/", "" );
142         tSrcAsString = tSrcAsString.replaceAll( "fitnesse.css", "fitnesse_base.css" );
143         tSrcAsString = tSrcAsString.replaceAll( "/files/javascript/", "" );
144         StringBuffer tFinal = new StringBuffer();
145 
146         int tStartIndex = tSrcAsString.indexOf( "<div class=\"sidebar\">" );
147         if ( tStartIndex != -1 )
148         {
149             int tEndIndex = tSrcAsString.indexOf( "<div class=\"mainbar\">" );
150             tFinal.append( tSrcAsString.substring( 0, tStartIndex ) );
151             tFinal.append( tSrcAsString.substring( tEndIndex, tSrcAsString.length() ) );
152             tSrcAsString = tFinal.toString();
153         }
154 
155         tStartIndex = tSrcAsString.indexOf( "<div class=\"header\">" );
156         if ( tStartIndex != -1 )
157         {
158             tFinal = new StringBuffer();
159             int tEndIndex = tSrcAsString.indexOf( "</div>\r\n" ) + "</div>\r\n".length();
160             tFinal.append( tSrcAsString.substring( 0, tStartIndex ) );
161             tFinal.append( tSrcAsString.substring( tEndIndex, tSrcAsString.length() ) );
162             tSrcAsString = tFinal.toString();
163         }
164 
165         if ( !new File( pFinalOutputName ).delete() )
166         {
167             throw new MojoExecutionException( "Unable to delete output file" );
168         }
169         FileWriter tWriter = null;
170         try
171         {
172             tWriter = new FileWriter( pFinalOutputName );
173             tWriter.write( tSrcAsString );
174         }
175         finally
176         {
177             if ( tWriter != null )
178             {
179                 tWriter.close();
180             }
181         }
182     }
183 
184     void checkFailure( String pFileContent, String pFileName )
185         throws MojoFailureException, MojoExecutionException
186     {
187         if ( isFailOnError() )
188         {
189             int tIndexOk = pFileContent.indexOf( START_REPORT_TAG_OK );
190             int tIndexKo = pFileContent.indexOf( START_REPORT_TAG_KO );
191             int tIndexKo2 = pFileContent.indexOf( START_REPORT_TAG_KO2 );
192             if ( tIndexOk == -1 )
193             {
194                 if ( ( tIndexKo == -1 ) && ( tIndexKo2 == -1 ) )
195                 {
196                     throw new MojoExecutionException( "Unable to find failure result into FitNesse page, resultFile=["
197                         + pFileName + "]." );
198                 }
199                 else
200                 {
201                     throw new MojoFailureException( "FitNesse page fail, resultFile=[" + pFileName + "]." );
202                 }
203             }
204             else
205             {
206                 if ( ( tIndexKo != -1 ) || ( tIndexKo2 != -1 ) )
207                 {
208                     throw new MojoExecutionException(
209                                                       "Find both success and fail result into FitNesse page , resultFile=["
210                                                           + pFileName + "]." );
211                 }
212             }
213         }
214 
215     }
216 
217     void getRemoteResource( String pUrl, OutputStream pOutStream, Fitnesse pServer )
218         throws MojoExecutionException
219     {
220         try
221         {
222             HttpClient tClient = new HttpClient();
223             getLog().info( "Request resources from [" + pUrl + "]" );
224             if ( pServer.getServerId() != null )
225             {
226                 tClient.getParams().setAuthenticationPreemptive( true );
227                 Credentials defaultcreds = getCredential( pServer.getServerId() );
228                 AuthScope tAuthScope = new AuthScope( pServer.getHostName(), pServer.getPort(), AuthScope.ANY_REALM );
229                 tClient.getState().setCredentials( tAuthScope, defaultcreds );
230                 getLog().info( "Use credential for remote connection" );
231             }
232             HttpMethod tMethod = new GetMethod( pUrl );
233             int tStatusCode = tClient.executeMethod( tMethod );
234             if ( tStatusCode != 200 )
235             {
236                 throw new MojoExecutionException( "Bad response code from resource [" + pUrl + "], return code=["
237                     + tStatusCode + "]" );
238             }
239 
240             InputStream tResponseStream = tMethod.getResponseBodyAsStream();
241             byte[] tbytes = new byte[512];
242             int tReadBytes = tResponseStream.read( tbytes );
243             while ( tReadBytes >= 0 )
244             {
245                 pOutStream.write( tbytes, 0, tReadBytes );
246                 tReadBytes = tResponseStream.read( tbytes );
247             }
248             pOutStream.flush();
249             tMethod.releaseConnection();
250         }
251         catch ( IOException e )
252         {
253             throw new MojoExecutionException( "Unable to read FitNesse server response.", e );
254         }
255         finally
256         {
257             try
258             {
259                 pOutStream.close();
260             }
261             catch ( IOException e )
262             {
263                 getLog().error( "Unable to close Stream." );
264             }
265         }
266     }
267 
268     public void setWorkingDir( String pWorkingDir )
269     {
270         workingDir = pWorkingDir;
271     }
272 
273     String getOutputFileName( Fitnesse pServer )
274     {
275         return getResultFileName( pServer, FitnesseAbstractMojo.OUTPUT_EXTENSION, "html" );
276     }
277 
278     String getOutputUrl( Fitnesse pServer )
279     {
280         return FITNESSE_RESULT_PREFIX + "_" + pServer.getHostName() + "_" + pServer.getPageName() + "_output.html";
281     }
282 
283 }