View Javadoc

1   package org.apache.maven.plugin.surefire.booterclient.output;
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.BufferedReader;
23  import java.io.IOException;
24  import java.io.StringReader;
25  import java.io.StringWriter;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Map;
29  import java.util.Properties;
30  import java.util.StringTokenizer;
31  import org.apache.maven.surefire.booter.ForkingRunListener;
32  import org.apache.maven.surefire.report.CategorizedReportEntry;
33  import org.apache.maven.surefire.report.ConsoleOutputReceiver;
34  import org.apache.maven.surefire.report.ConsoleLogger;
35  import org.apache.maven.surefire.report.ReportEntry;
36  import org.apache.maven.surefire.report.ReporterException;
37  import org.apache.maven.surefire.report.ReporterFactory;
38  import org.apache.maven.surefire.report.RunListener;
39  import org.apache.maven.surefire.report.SimpleReportEntry;
40  import org.apache.maven.surefire.report.StackTraceWriter;
41  import org.apache.maven.surefire.util.NestedRuntimeException;
42  import org.apache.maven.surefire.util.internal.StringUtils;
43  import org.codehaus.plexus.util.cli.StreamConsumer;
44  
45  /**
46   * Knows how to reconstruct *all* the state transmitted over stdout by the forked process.
47   *
48   * @author Kristian Rosenvold
49   */
50  public class ForkClient
51      implements StreamConsumer
52  {
53      private final ReporterFactory providerReporterFactory;
54  
55      private final Map testSetReporters = Collections.synchronizedMap( new HashMap() );
56  
57      private final Properties testVmSystemProperties;
58  
59      public ForkClient( ReporterFactory providerReporterFactory, Properties testVmSystemProperties )
60      {
61          this.providerReporterFactory = providerReporterFactory;
62          this.testVmSystemProperties = testVmSystemProperties;
63      }
64  
65      public void consumeLine( String s )
66      {
67          try
68          {
69              if ( s.length() == 0 )
70              {
71                  return;
72              }
73              final byte operationId = (byte) s.charAt( 0 );
74              int commma = s.indexOf( ",", 3 );
75              if ( commma < 0 )
76              {
77                  System.out.println( s );
78                  return;
79              }
80              final Integer channelNumber = new Integer( Integer.parseInt( s.substring( 2, commma ), 16 ) );
81              RunListener reporter = (RunListener) testSetReporters.get( channelNumber );
82              if ( reporter == null )
83              {
84                  reporter = providerReporterFactory.createReporter();
85                  //reporter = new AsynchRunListener( reporter, "ForkClient" );
86                  testSetReporters.put( channelNumber, reporter );
87              }
88              int rest = s.indexOf( ",", commma );
89              final String remaining = s.substring( rest + 1 );
90  
91              switch ( operationId )
92              {
93                  case ForkingRunListener.BOOTERCODE_TESTSET_STARTING:
94                      reporter.testSetStarting( createReportEntry( remaining ) );
95                      break;
96                  case ForkingRunListener.BOOTERCODE_TESTSET_COMPLETED:
97                      reporter.testSetCompleted( createReportEntry( remaining ) );
98                      break;
99                  case ForkingRunListener.BOOTERCODE_TEST_STARTING:
100                     reporter.testStarting( createReportEntry( remaining) );
101                     break;
102                 case ForkingRunListener.BOOTERCODE_TEST_SUCCEEDED:
103                     reporter.testSucceeded( createReportEntry( remaining ) );
104                     break;
105                 case ForkingRunListener.BOOTERCODE_TEST_FAILED:
106                     reporter.testFailed( createReportEntry( remaining ) );
107                     break;
108                 case ForkingRunListener.BOOTERCODE_TEST_SKIPPED:
109                     reporter.testSkipped( createReportEntry( remaining ) );
110                     break;
111                 case ForkingRunListener.BOOTERCODE_TEST_ERROR:
112                     reporter.testError( createReportEntry( remaining ) );
113                     break;
114                 case ForkingRunListener.BOOTERCODE_TEST_ASSUMPTIONFAILURE:
115                     reporter.testAssumptionFailure( createReportEntry( remaining ) );
116                     break;
117                 case ForkingRunListener.BOOTERCODE_SYSPROPS:
118                     int keyEnd = remaining.indexOf( "," );
119                     StringWriter key = new StringWriter();
120                     StringWriter value = new StringWriter();
121                     StringUtils.unescapeJava( key, remaining.substring( 0, keyEnd ) );
122                     StringUtils.unescapeJava( value, remaining.substring( keyEnd + 1 ) );
123 
124                     synchronized ( testVmSystemProperties )
125                     {
126                         testVmSystemProperties.put( key, value );
127                     }
128                     break;
129                 case ForkingRunListener.BOOTERCODE_STDOUT:
130                     byte[] bytes = new byte[remaining.length() * 2];
131                     int len = StringUtils.unescapeJava( bytes, remaining );
132                     ( (ConsoleOutputReceiver) reporter ).writeTestOutput( bytes, 0, len, true );
133                     break;
134                 case ForkingRunListener.BOOTERCODE_STDERR:
135                     bytes = new byte[remaining.length() * 2];
136                     len = StringUtils.unescapeJava( bytes, remaining );
137                     ( (ConsoleOutputReceiver) reporter ).writeTestOutput( bytes, 0, len, false );
138                     break;
139                 case ForkingRunListener.BOOTERCODE_CONSOLE:
140                     ( (ConsoleLogger) reporter ).info( createConsoleMessage( remaining ) );
141                     break;
142                 default:
143                     System.out.println( s );
144             }
145         }
146         catch ( NumberFormatException e )
147         {
148             System.out.println( s );
149         }
150         catch ( ReporterException e )
151         {
152             throw new NestedRuntimeException( e );
153         }
154     }
155 
156     public void consumeMultiLineContent( String s )
157         throws IOException
158     {
159         BufferedReader stringReader = new BufferedReader( new StringReader( s ) );
160         String s1;
161         while ( ( s1 = stringReader.readLine() ) != null )
162         {
163             consumeLine( s1 );
164         }
165     }
166 
167     private String createConsoleMessage( String remaining )
168     {
169         return unescape( remaining );
170     }
171 
172     private ReportEntry createReportEntry( String untokenized)
173     {
174         StringTokenizer tokens = new StringTokenizer(untokenized, ",");
175         try
176         {
177             String source = tokens.nextToken();
178             String name = tokens.nextToken();
179             String group = nullableCsv( tokens.nextToken() );
180             String elapsedStr = tokens.nextToken();
181             Integer elapsed = "null".equals( elapsedStr ) ? null : Integer.decode( elapsedStr );
182             final StackTraceWriter stackTraceWriter =
183                 tokens.hasMoreTokens() ? deserializeStackStraceWriter( tokens ) : null;
184 
185             return group != null
186                 ? new CategorizedReportEntry( source, name, group, stackTraceWriter, elapsed )
187                 : new SimpleReportEntry( source, name, stackTraceWriter, elapsed );
188         }
189         catch ( RuntimeException e )
190         {
191             throw new RuntimeException( untokenized, e );
192         }
193     }
194 
195     private StackTraceWriter deserializeStackStraceWriter( StringTokenizer tokens )
196     {
197         StackTraceWriter stackTraceWriter;
198         String stackTraceMessage = nullableCsv( tokens.nextToken() );
199         String stackTrace = tokens.hasMoreTokens() ? nullableCsv( tokens.nextToken() ) : null;
200         stackTraceWriter =
201             stackTrace != null ? new DeserializedStacktraceWriter( stackTraceMessage, stackTrace ) : null;
202         return stackTraceWriter;
203     }
204 
205     private String nullableCsv( String source )
206     {
207         if ( "null".equals( source ) )
208         {
209             return null;
210         }
211         return unescape( source );
212     }
213 
214     private String unescape( String source )
215     {
216         StringWriter stringWriter = new StringWriter( source.length() );
217 
218         StringUtils.unescapeJava( stringWriter, source );
219         return stringWriter.getBuffer().toString();
220     }
221 
222     /**
223      * Used when getting reporters on the plugin side of a fork.
224      *
225      * @param channelNumber The logical channel number
226      * @return A mock provider reporter
227      */
228     public RunListener getReporter( Integer channelNumber )
229     {
230         return (RunListener) testSetReporters.get( channelNumber );
231     }
232 
233 
234     public void close()
235     {
236         /*Iterator iter = testSetReporters.values().iterator();
237         while( iter.hasNext() )
238         {
239             ((AsynchRunListener)iter.next()).close();
240         } */
241     }
242 }