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