1 package org.apache.maven.surefire.booter;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.PrintStream;
23 import java.util.Enumeration;
24 import java.util.Properties;
25 import org.apache.maven.surefire.report.ConsoleLogger;
26 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
27 import org.apache.maven.surefire.report.ReportEntry;
28 import org.apache.maven.surefire.report.RunListener;
29 import org.apache.maven.surefire.report.SafeThrowable;
30 import org.apache.maven.surefire.report.StackTraceWriter;
31 import org.apache.maven.surefire.util.internal.ByteBuffer;
32 import org.apache.maven.surefire.util.internal.StringUtils;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class ForkingRunListener
52 implements RunListener, ConsoleLogger, ConsoleOutputReceiver
53 {
54 public static final byte BOOTERCODE_TESTSET_STARTING = (byte) '1';
55
56 public static final byte BOOTERCODE_TESTSET_COMPLETED = (byte) '2';
57
58 public static final byte BOOTERCODE_STDOUT = (byte) '3';
59
60 public static final byte BOOTERCODE_STDERR = (byte) '4';
61
62 public static final byte BOOTERCODE_TEST_STARTING = (byte) '5';
63
64 public static final byte BOOTERCODE_TEST_SUCCEEDED = (byte) '6';
65
66 public static final byte BOOTERCODE_TEST_ERROR = (byte) '7';
67
68 public static final byte BOOTERCODE_TEST_FAILED = (byte) '8';
69
70 public static final byte BOOTERCODE_TEST_SKIPPED = (byte) '9';
71
72 public static final byte BOOTERCODE_TEST_ASSUMPTIONFAILURE = (byte) 'G';
73
74 public static final byte BOOTERCODE_CONSOLE = (byte) 'H';
75
76 public static final byte BOOTERCODE_SYSPROPS = (byte) 'I';
77
78 public static final byte BOOTERCODE_NEXT_TEST = (byte) 'N';
79
80 public static final byte BOOTERCODE_ERROR = (byte) 'X';
81
82 public static final byte BOOTERCODE_BYE = (byte) 'Z';
83
84
85 private final PrintStream target;
86
87 private final Integer testSetChannelId;
88
89 private final boolean trimStackTraces;
90
91 private final byte[] stdOutHeader;
92
93 private final byte[] stdErrHeader;
94
95 public ForkingRunListener( PrintStream target, int testSetChannelId, boolean trimStackTraces )
96 {
97 this.target = target;
98 this.testSetChannelId = testSetChannelId;
99 this.trimStackTraces = trimStackTraces;
100 stdOutHeader = createHeader( BOOTERCODE_STDOUT, testSetChannelId );
101 stdErrHeader = createHeader( BOOTERCODE_STDERR, testSetChannelId );
102 sendProps();
103 }
104
105 public void testSetStarting( ReportEntry report )
106 {
107 target.print( toString( BOOTERCODE_TESTSET_STARTING, report, testSetChannelId ) );
108 }
109
110 public void testSetCompleted( ReportEntry report )
111 {
112 target.print( toString( BOOTERCODE_TESTSET_COMPLETED, report, testSetChannelId ) );
113 }
114
115 public void testStarting( ReportEntry report )
116 {
117 target.print( toString( BOOTERCODE_TEST_STARTING, report, testSetChannelId ) );
118 }
119
120 public void testSucceeded( ReportEntry report )
121 {
122 target.print( toString( BOOTERCODE_TEST_SUCCEEDED, report, testSetChannelId ) );
123 }
124
125 public void testAssumptionFailure( ReportEntry report )
126 {
127 target.print( toString( BOOTERCODE_TEST_ASSUMPTIONFAILURE, report, testSetChannelId ) );
128 }
129
130 public void testError( ReportEntry report )
131 {
132 target.print( toString( BOOTERCODE_TEST_ERROR, report, testSetChannelId ) );
133 }
134
135 public void testFailed( ReportEntry report )
136 {
137 target.print( toString( BOOTERCODE_TEST_FAILED, report, testSetChannelId ) );
138 }
139
140 public void testSkipped( ReportEntry report )
141 {
142 target.print( toString( BOOTERCODE_TEST_SKIPPED, report, testSetChannelId ) );
143 }
144
145 void sendProps()
146 {
147 Properties systemProperties = System.getProperties();
148
149 if ( systemProperties != null )
150 {
151 Enumeration propertyKeys = systemProperties.propertyNames();
152
153 while ( propertyKeys.hasMoreElements() )
154 {
155 String key = (String) propertyKeys.nextElement();
156
157 String value = systemProperties.getProperty( key );
158
159 if ( value == null )
160 {
161 value = "null";
162 }
163 target.print( toPropertyString( key, value ) );
164 }
165 }
166 }
167
168 public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
169 {
170 byte[] header = stdout ? stdOutHeader : stdErrHeader;
171 byte[] content =
172 new byte[buf.length * 6 + 1];
173 int i = StringUtils.escapeJavaStyleString( content, 0, buf, off, len );
174 content[i++] = (byte) '\n';
175
176 synchronized ( target )
177 {
178 target.write( header, 0, header.length );
179 target.write( content, 0, i );
180 }
181 }
182
183 public static byte[] createHeader( byte booterCode, int testSetChannel )
184 {
185 byte[] header = new byte[7];
186 header[0] = booterCode;
187 header[1] = (byte) ',';
188 header[6] = (byte) ',';
189
190 int i = testSetChannel;
191 int charPos = 6;
192 int radix = 1 << 4;
193 int mask = radix - 1;
194 do
195 {
196 header[--charPos] = (byte) digits[i & mask];
197 i >>>= 4;
198 }
199 while ( i != 0 );
200
201 while ( charPos > 2 )
202 {
203 header[--charPos] = (byte) '0';
204 }
205 return header;
206 }
207
208 private final static char[] digits =
209 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
210 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
211
212
213 public void info( String message )
214 {
215 byte[] buf = message.getBytes();
216 ByteBuffer byteBuffer = new ByteBuffer( 7 + buf.length * 6 );
217 byteBuffer.append( BOOTERCODE_CONSOLE );
218 byteBuffer.comma();
219 byteBuffer.append( testSetChannelId );
220 byteBuffer.comma();
221 final int i =
222 StringUtils.escapeJavaStyleString( byteBuffer.getData(), byteBuffer.getlength(), buf, 0, buf.length );
223 byteBuffer.advance( i );
224 byteBuffer.append( '\n' );
225 synchronized ( target )
226 {
227 target.write( byteBuffer.getData(), 0, byteBuffer.getlength() );
228 target.flush();
229 }
230 }
231
232 private String toPropertyString( String key, String value )
233 {
234 StringBuffer stringBuffer = new StringBuffer();
235
236 append( stringBuffer, BOOTERCODE_SYSPROPS );comma( stringBuffer );
237 append( stringBuffer, Integer.toHexString( testSetChannelId ) );comma( stringBuffer );
238
239 StringUtils.escapeJavaStyleString( stringBuffer, key );
240 append( stringBuffer, "," );
241 StringUtils.escapeJavaStyleString( stringBuffer, value );
242 stringBuffer.append( "\n" );
243 return stringBuffer.toString();
244 }
245
246 private String toString( byte operationCode, ReportEntry reportEntry, Integer testSetChannelId )
247 {
248 StringBuffer stringBuffer = new StringBuffer();
249 append( stringBuffer, operationCode ); comma( stringBuffer );
250 append( stringBuffer, Integer.toHexString( testSetChannelId ) );comma( stringBuffer );
251
252 nullableEncoding( stringBuffer, reportEntry.getSourceName() );
253 comma( stringBuffer );
254 nullableEncoding( stringBuffer, reportEntry.getName() );
255 comma( stringBuffer );
256 nullableEncoding( stringBuffer, reportEntry.getGroup() );
257 comma( stringBuffer );
258 nullableEncoding( stringBuffer, reportEntry.getMessage() );
259 comma( stringBuffer );
260 nullableEncoding( stringBuffer, reportEntry.getElapsed() );
261 encode( stringBuffer, reportEntry.getStackTraceWriter() );
262 stringBuffer.append( "\n" );
263 return stringBuffer.toString();
264 }
265
266 private static void comma( StringBuffer stringBuffer )
267 {
268 stringBuffer.append( "," );
269 }
270
271 private ForkingRunListener append( StringBuffer stringBuffer, String message )
272 {
273 stringBuffer.append( encode( message ) );
274 return this;
275 }
276
277 private ForkingRunListener append( StringBuffer stringBuffer, byte b )
278 {
279 stringBuffer.append( (char) b );
280 return this;
281 }
282
283 private void nullableEncoding( StringBuffer stringBuffer, Integer source )
284 {
285 if ( source == null )
286 {
287 stringBuffer.append( "null" );
288 }
289 else
290 {
291 stringBuffer.append( source.toString() );
292 }
293 }
294
295 private String encode( String source )
296 {
297 return source;
298 }
299
300
301 private static void nullableEncoding( StringBuffer stringBuffer, String source )
302 {
303 if ( source == null || source.length() == 0 )
304 {
305 stringBuffer.append( "null" );
306 }
307 else
308 {
309 StringUtils.escapeJavaStyleString( stringBuffer, source );
310 }
311 }
312
313 private void encode( StringBuffer stringBuffer, StackTraceWriter stackTraceWriter )
314 {
315 encode( stringBuffer, stackTraceWriter, trimStackTraces );
316 }
317
318 public static void encode( StringBuffer stringBuffer, StackTraceWriter stackTraceWriter, boolean trimStackTraces )
319 {
320 if ( stackTraceWriter != null )
321 {
322 comma( stringBuffer );
323
324 final SafeThrowable throwable = stackTraceWriter.getThrowable();
325 if ( throwable != null )
326 {
327 String message = throwable.getLocalizedMessage();
328 nullableEncoding( stringBuffer, message );
329 }
330 comma( stringBuffer );
331 nullableEncoding( stringBuffer, stackTraceWriter.smartTrimmedStackTrace() );
332 comma( stringBuffer );
333 nullableEncoding( stringBuffer, trimStackTraces
334 ? stackTraceWriter.writeTrimmedTraceToString()
335 : stackTraceWriter.writeTraceToString() );
336 }
337 }
338 }