1 package org.apache.maven.plugin.surefire.extensions;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.plugin.surefire.booterclient.output.DeserializedStacktraceWriter;
23 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessEventListener;
24 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessEventNotifier;
25 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessExitErrorListener;
26 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessPropertyEventListener;
27 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessReportEventListener;
28 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessStackTraceEventListener;
29 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessStandardOutErrEventListener;
30 import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessStringEventListener;
31 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
32 import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
33 import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder;
34 import org.apache.maven.surefire.api.event.Event;
35 import org.apache.maven.surefire.extensions.EventHandler;
36 import org.apache.maven.surefire.extensions.ForkNodeArguments;
37 import org.apache.maven.surefire.extensions.util.CountdownCloseable;
38 import org.apache.maven.surefire.api.report.ReportEntry;
39 import org.apache.maven.surefire.api.report.RunMode;
40 import org.apache.maven.surefire.api.report.SafeThrowable;
41 import org.apache.maven.surefire.api.report.StackTraceWriter;
42 import org.apache.maven.surefire.api.util.internal.ObjectUtils;
43 import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
44 import org.junit.Rule;
45 import org.junit.Test;
46 import org.junit.experimental.runners.Enclosed;
47 import org.junit.experimental.theories.DataPoints;
48 import org.junit.experimental.theories.FromDataPoints;
49 import org.junit.experimental.theories.Theories;
50 import org.junit.experimental.theories.Theory;
51 import org.junit.rules.ExpectedException;
52 import org.junit.runner.RunWith;
53 import org.mockito.ArgumentCaptor;
54 import org.powermock.core.classloader.annotations.PowerMockIgnore;
55 import org.powermock.modules.junit4.PowerMockRunner;
56
57 import javax.annotation.Nonnull;
58 import java.io.ByteArrayInputStream;
59 import java.io.ByteArrayOutputStream;
60 import java.io.Closeable;
61 import java.io.File;
62 import java.io.LineNumberReader;
63 import java.io.PrintStream;
64 import java.io.StringReader;
65 import java.nio.ByteBuffer;
66 import java.nio.channels.ReadableByteChannel;
67 import java.nio.charset.Charset;
68 import java.util.Map;
69 import java.util.concurrent.BlockingQueue;
70 import java.util.concurrent.LinkedTransferQueue;
71 import java.util.concurrent.TimeUnit;
72 import java.util.concurrent.atomic.AtomicBoolean;
73 import java.util.concurrent.atomic.AtomicInteger;
74
75 import static java.lang.String.format;
76 import static java.nio.charset.StandardCharsets.UTF_8;
77 import static java.util.Arrays.copyOfRange;
78 import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
79 import static org.apache.maven.surefire.shared.codec.binary.Base64.encodeBase64String;
80 import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
81 import static org.apache.maven.surefire.api.util.internal.Channels.newChannel;
82 import static org.fest.assertions.Assertions.assertThat;
83 import static org.fest.assertions.Index.atIndex;
84 import static org.junit.Assert.assertTrue;
85 import static org.junit.rules.ExpectedException.none;
86 import static org.mockito.ArgumentMatchers.anyString;
87 import static org.mockito.Mockito.mock;
88 import static org.mockito.Mockito.times;
89 import static org.mockito.Mockito.verify;
90 import static org.mockito.Mockito.when;
91
92
93
94
95
96
97
98 @RunWith( Enclosed.class )
99 public class ForkedProcessEventNotifierTest
100 {
101
102
103
104 @RunWith( PowerMockRunner.class )
105 @PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
106 public static class DecoderOperationsTest
107 {
108 @Rule
109 public final ExpectedException rule = none();
110
111 @Test
112 public void shouldBeFailSafe()
113 {
114 assertThat( EventConsumerThread.decode( null, UTF_8 ) ).isNull();
115 assertThat( EventConsumerThread.decode( "-", UTF_8 ) ).isNull();
116 assertThat( EventConsumerThread.decodeToInteger( null ) ).isNull();
117 assertThat( EventConsumerThread.decodeToInteger( "-" ) ).isNull();
118 }
119
120 @Test
121 public void shouldHaveSystemProperty() throws Exception
122 {
123 final Stream out = Stream.newStream();
124 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
125 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
126 Map<String, String> props = ObjectUtils.systemProps();
127 encoder.sendSystemProperties( props );
128 wChannel.close();
129
130 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
131 PropertyEventAssertionListener listener = new PropertyEventAssertionListener();
132 notifier.setSystemPropertiesListener( listener );
133
134 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
135
136 EH eventHandler = new EH();
137 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
138 ConsoleLogger logger = mock( ConsoleLogger.class );
139 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
140 when( arguments.getConsoleLogger() ).thenReturn( logger );
141 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
142 {
143 t.start();
144 for ( int i = 0; i < props.size(); i++ )
145 {
146 notifier.notifyEvent( eventHandler.pullEvent() );
147 }
148 }
149
150 assertThat( listener.counter.get() )
151 .isEqualTo( props.size() );
152 }
153
154 @Test
155 public void shouldRecognizeEmptyStream4ReportEntry()
156 {
157 ReportEntry reportEntry = EventConsumerThread.decodeReportEntry( null, null, null, "", "", null, null, "",
158 "", "", null );
159 assertThat( reportEntry ).isNull();
160
161 reportEntry = EventConsumerThread.decodeReportEntry( UTF_8, "", "", "", "", "", "", "-", "", "", "" );
162 assertThat( reportEntry ).isNotNull();
163 assertThat( reportEntry.getStackTraceWriter() ).isNotNull();
164 assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() ).isEmpty();
165 assertThat( reportEntry.getStackTraceWriter().writeTraceToString() ).isEmpty();
166 assertThat( reportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEmpty();
167 assertThat( reportEntry.getSourceName() ).isEmpty();
168 assertThat( reportEntry.getSourceText() ).isEmpty();
169 assertThat( reportEntry.getName() ).isEmpty();
170 assertThat( reportEntry.getNameText() ).isEmpty();
171 assertThat( reportEntry.getGroup() ).isEmpty();
172 assertThat( reportEntry.getNameWithGroup() ).isEmpty();
173 assertThat( reportEntry.getMessage() ).isEmpty();
174 assertThat( reportEntry.getElapsed() ).isNull();
175
176 rule.expect( NumberFormatException.class );
177 EventConsumerThread.decodeReportEntry( UTF_8, "", "", "", "", "", "", "", "", "", "" );
178 }
179
180 @Test
181 @SuppressWarnings( "checkstyle:magicnumber" )
182 public void testCreatingReportEntry()
183 {
184 final String exceptionMessage = "msg";
185 final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
186
187 final String smartStackTrace = "MyTest:86 >> Error";
188 final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
189
190 final String stackTrace = "Exception: msg\ntrace line 1\ntrace line 2";
191 final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
192
193 final String trimmedStackTrace = "trace line 1\ntrace line 2";
194 final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
195
196 SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
197 StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
198 when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
199 when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
200 when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
201 when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
202
203 ReportEntry reportEntry = mock( ReportEntry.class );
204 when( reportEntry.getElapsed() ).thenReturn( 102 );
205 when( reportEntry.getGroup() ).thenReturn( "this group" );
206 when( reportEntry.getMessage() ).thenReturn( "skipped test" );
207 when( reportEntry.getName() ).thenReturn( "my test" );
208 when( reportEntry.getNameText() ).thenReturn( "my display name" );
209 when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
210 when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
211 when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
212 when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
213
214 String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
215 String encodedSourceText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceText() ) ) );
216 String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
217 String encodedText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getNameText() ) ) );
218 String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
219 String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
220
221 ReportEntry decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName,
222 encodedSourceText, encodedName, encodedText, encodedGroup, encodedMessage, "-", null, null, null );
223
224 assertThat( decodedReportEntry ).isNotNull();
225 assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
226 assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
227 assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
228 assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
229 assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
230 assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
231 assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
232
233 decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
234 encodedName, encodedText, encodedGroup, encodedMessage, "-", encodedExceptionMsg,
235 encodedSmartStackTrace, null );
236
237 assertThat( decodedReportEntry ).isNotNull();
238 assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
239 assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
240 assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
241 assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
242 assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
243 assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
244 assertThat( decodedReportEntry.getElapsed() ).isNull();
245 assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
246 assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
247 .isEqualTo( exceptionMessage );
248 assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
249 .isEqualTo( smartStackTrace );
250 assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
251 .isNull();
252
253 decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
254 encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
255 encodedSmartStackTrace, null );
256
257 assertThat( decodedReportEntry ).isNotNull();
258 assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
259 assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
260 assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
261 assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
262 assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
263 assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
264 assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
265 assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
266 assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
267 .isEqualTo( exceptionMessage );
268 assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
269 .isEqualTo( smartStackTrace );
270 assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
271 .isNull();
272
273 decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
274 encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
275 encodedSmartStackTrace, encodedStackTrace );
276
277 assertThat( decodedReportEntry ).isNotNull();
278 assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
279 assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
280 assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
281 assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
282 assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
283 assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
284 assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
285 assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
286 assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
287 assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
288 .isEqualTo( exceptionMessage );
289 assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
290 .isEqualTo( smartStackTrace );
291 assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( stackTrace );
292 assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEqualTo( stackTrace );
293
294 decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
295 encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
296 encodedSmartStackTrace, encodedTrimmedStackTrace );
297
298 assertThat( decodedReportEntry ).isNotNull();
299 assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
300 assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
301 assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
302 assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
303 assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
304 assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
305 assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
306 assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
307 assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
308 assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
309 .isEqualTo( exceptionMessage );
310 assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
311 .isEqualTo( smartStackTrace );
312 assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( trimmedStackTrace );
313 assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() )
314 .isEqualTo( trimmedStackTrace );
315 }
316
317 @Test
318 public void shouldSendByeEvent() throws Exception
319 {
320 Stream out = Stream.newStream();
321 LegacyMasterProcessChannelEncoder encoder =
322 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
323 encoder.bye();
324 String read = new String( out.toByteArray(), UTF_8 );
325
326 assertThat( read )
327 .isEqualTo( ":maven-surefire-event:bye:\n" );
328
329 LineNumberReader lines = out.newReader( UTF_8 );
330
331 final String cmd = lines.readLine();
332 assertThat( cmd )
333 .isNotNull();
334
335 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
336
337 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
338 EventAssertionListener listener = new EventAssertionListener();
339 notifier.setByeListener( listener );
340
341 EH eventHandler = new EH();
342 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
343 ConsoleLogger logger = mock( ConsoleLogger.class );
344 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
345 when( arguments.getConsoleLogger() ).thenReturn( logger );
346 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
347 {
348 t.start();
349 notifier.notifyEvent( eventHandler.pullEvent() );
350 }
351
352 assertThat( listener.called.get() )
353 .isTrue();
354 }
355
356 @Test
357 public void shouldSendStopOnNextTestEvent() throws Exception
358 {
359 Stream out = Stream.newStream();
360 LegacyMasterProcessChannelEncoder encoder =
361 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
362 encoder.stopOnNextTest();
363 String read = new String( out.toByteArray(), UTF_8 );
364
365 assertThat( read )
366 .isEqualTo( ":maven-surefire-event:stop-on-next-test:\n" );
367
368 LineNumberReader lines = out.newReader( UTF_8 );
369
370 final String cmd = lines.readLine();
371 assertThat( cmd )
372 .isNotNull();
373
374 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
375
376 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
377 EventAssertionListener listener = new EventAssertionListener();
378 notifier.setStopOnNextTestListener( listener );
379
380 EH eventHandler = new EH();
381 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
382 ConsoleLogger logger = mock( ConsoleLogger.class );
383 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
384 when( arguments.getConsoleLogger() ).thenReturn( logger );
385 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
386 {
387 t.start();
388 notifier.notifyEvent( eventHandler.pullEvent() );
389 }
390
391 assertThat( listener.called.get() )
392 .isTrue();
393 }
394
395 @Test
396 public void shouldCorrectlyDecodeStackTracesWithEmptyStringTraceMessages() throws Exception
397 {
398 String exceptionMessage = "";
399 String smartStackTrace = "JUnit5Test.failWithEmptyString:16";
400 String exceptionStackTrace = "org.opentest4j.AssertionFailedError: \n"
401 + "\tat JUnit5Test.failWithEmptyString(JUnit5Test.java:16)\n";
402
403 StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
404 SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
405 when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
406 when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
407 when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
408 when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
409
410 ReportEntry reportEntry = mock( ReportEntry.class );
411 when( reportEntry.getElapsed() ).thenReturn( 7 );
412 when( reportEntry.getGroup() ).thenReturn( null );
413 when( reportEntry.getMessage() ).thenReturn( null );
414 when( reportEntry.getName() ).thenReturn( "failWithEmptyString" );
415 when( reportEntry.getNameWithGroup() ).thenReturn( "JUnit5Test" );
416 when( reportEntry.getSourceName() ).thenReturn( "JUnit5Test" );
417 when( reportEntry.getSourceText() ).thenReturn( null );
418 when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
419
420 final Stream out = Stream.newStream();
421 LegacyMasterProcessChannelEncoder encoder =
422 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
423 encoder.testFailed( reportEntry, true );
424
425 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
426
427 final ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
428 ReportEventAssertionListener listener = new ReportEventAssertionListener( reportEntry, true );
429 notifier.setTestFailedListener( listener );
430
431 EH eventHandler = new EH();
432 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
433 ConsoleLogger logger = mock( ConsoleLogger.class );
434 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
435 when( arguments.getConsoleLogger() ).thenReturn( logger );
436 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
437 {
438 t.start();
439 notifier.notifyEvent( eventHandler.pullEvent() );
440 }
441
442 assertThat( listener.called.get() )
443 .isTrue();
444 }
445
446 @Test
447 public void shouldSendNextTestEvent() throws Exception
448 {
449 final Stream out = Stream.newStream();
450 LegacyMasterProcessChannelEncoder encoder =
451 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
452 encoder.acquireNextTest();
453 String read = new String( out.toByteArray(), UTF_8 );
454
455 assertThat( read )
456 .isEqualTo( ":maven-surefire-event:next-test:\n" );
457
458 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
459
460 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
461 EventAssertionListener listener = new EventAssertionListener();
462 notifier.setAcquireNextTestListener( listener );
463
464 EH eventHandler = new EH();
465 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
466 ConsoleLogger logger = mock( ConsoleLogger.class );
467 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
468 when( arguments.getConsoleLogger() ).thenReturn( logger );
469 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
470 {
471 t.start();
472 notifier.notifyEvent( eventHandler.pullEvent() );
473 }
474
475 assertThat( listener.called.get() )
476 .isTrue();
477 }
478
479 @Test
480 public void testConsole() throws Exception
481 {
482 final Stream out = Stream.newStream();
483 LegacyMasterProcessChannelEncoder encoder =
484 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
485 encoder.consoleInfoLog( "msg" );
486
487 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
488
489 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
490 StringEventAssertionListener listener = new StringEventAssertionListener( "msg" );
491 notifier.setConsoleInfoListener( listener );
492
493 EH eventHandler = new EH();
494 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
495 ConsoleLogger logger = mock( ConsoleLogger.class );
496 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
497 when( arguments.getConsoleLogger() ).thenReturn( logger );
498 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
499 {
500 t.start();
501 notifier.notifyEvent( eventHandler.pullEvent() );
502 }
503
504 assertThat( listener.called.get() )
505 .isTrue();
506 }
507
508 @Test
509 public void testError() throws Exception
510 {
511 final Stream out = Stream.newStream();
512 LegacyMasterProcessChannelEncoder encoder =
513 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
514 encoder.consoleErrorLog( "msg" );
515
516 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
517
518 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
519 StackTraceEventListener listener = new StackTraceEventListener( "msg", null, null );
520 notifier.setConsoleErrorListener( listener );
521
522 EH eventHandler = new EH();
523 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
524 ConsoleLogger logger = mock( ConsoleLogger.class );
525 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
526 when( arguments.getConsoleLogger() ).thenReturn( logger );
527 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
528 {
529 t.start();
530 notifier.notifyEvent( eventHandler.pullEvent() );
531 }
532
533 assertThat( listener.called.get() )
534 .isTrue();
535 }
536
537 @Test
538 public void testErrorWithException() throws Exception
539 {
540 final Stream out = Stream.newStream();
541 LegacyMasterProcessChannelEncoder encoder =
542 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
543 Throwable throwable = new Throwable( "msg" );
544 encoder.consoleErrorLog( throwable );
545
546 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
547
548 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
549 String stackTrace = ConsoleLoggerUtils.toString( throwable );
550 StackTraceEventListener listener = new StackTraceEventListener( "msg", null, stackTrace );
551 notifier.setConsoleErrorListener( listener );
552
553 EH eventHandler = new EH();
554 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
555 ConsoleLogger logger = mock( ConsoleLogger.class );
556 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
557 when( arguments.getConsoleLogger() ).thenReturn( logger );
558 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
559 {
560 t.start();
561 notifier.notifyEvent( eventHandler.pullEvent() );
562 }
563
564 assertThat( listener.called.get() )
565 .isTrue();
566 }
567
568 @Test
569 public void testErrorWithStackTraceWriter() throws Exception
570 {
571 final Stream out = Stream.newStream();
572
573 LegacyMasterProcessChannelEncoder encoder =
574 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
575 StackTraceWriter stackTraceWriter = new DeserializedStacktraceWriter( "1", "2", "3" );
576 encoder.consoleErrorLog( stackTraceWriter, false );
577
578 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
579
580 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
581 StackTraceEventListener listener = new StackTraceEventListener( "1", "2", "3" );
582 notifier.setConsoleErrorListener( listener );
583
584 EH eventHandler = new EH();
585 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
586 ConsoleLogger logger = mock( ConsoleLogger.class );
587 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
588 when( arguments.getConsoleLogger() ).thenReturn( logger );
589 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
590 {
591 t.start();
592 notifier.notifyEvent( eventHandler.pullEvent() );
593 }
594
595 assertThat( listener.called.get() )
596 .isTrue();
597 }
598
599 @Test
600 public void testDebug() throws Exception
601 {
602 final Stream out = Stream.newStream();
603
604 LegacyMasterProcessChannelEncoder encoder =
605 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
606 encoder.consoleDebugLog( "msg" );
607
608 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
609
610 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
611 StringEventAssertionListener listener = new StringEventAssertionListener( "msg" );
612 notifier.setConsoleDebugListener( listener );
613
614 EH eventHandler = new EH();
615 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
616 ConsoleLogger logger = mock( ConsoleLogger.class );
617 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
618 when( arguments.getConsoleLogger() ).thenReturn( logger );
619 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
620 {
621 t.start();
622 notifier.notifyEvent( eventHandler.pullEvent() );
623 }
624
625 assertThat( listener.called.get() )
626 .isTrue();
627
628 assertThat( listener.msg )
629 .isEqualTo( "msg" );
630 }
631
632 @Test
633 public void testWarning() throws Exception
634 {
635 final Stream out = Stream.newStream();
636
637 LegacyMasterProcessChannelEncoder encoder =
638 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
639 encoder.consoleWarningLog( "msg" );
640
641 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
642
643 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
644 StringEventAssertionListener listener = new StringEventAssertionListener( "msg" );
645 notifier.setConsoleWarningListener( listener );
646
647 EH eventHandler = new EH();
648 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
649 ConsoleLogger logger = mock( ConsoleLogger.class );
650 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
651 when( arguments.getConsoleLogger() ).thenReturn( logger );
652 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
653 {
654 t.start();
655 notifier.notifyEvent( eventHandler.pullEvent() );
656 }
657
658 assertThat( listener.called.get() )
659 .isTrue();
660 }
661
662 @Test
663 public void testStdOutStream() throws Exception
664 {
665 final Stream out = Stream.newStream();
666 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
667 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
668 encoder.stdOut( "msg", false );
669 wChannel.close();
670
671 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
672
673 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
674 StandardOutErrEventAssertionListener listener =
675 new StandardOutErrEventAssertionListener( NORMAL_RUN, "msg", false );
676 notifier.setStdOutListener( listener );
677
678 EH eventHandler = new EH();
679 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
680 ConsoleLogger logger = mock( ConsoleLogger.class );
681 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
682 when( arguments.getConsoleLogger() ).thenReturn( logger );
683 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
684 {
685 t.start();
686 notifier.notifyEvent( eventHandler.pullEvent() );
687 }
688
689 assertThat( listener.called.get() )
690 .isTrue();
691 }
692
693 @Test
694 public void testStdOutStreamPrint() throws Exception
695 {
696 final Stream out = Stream.newStream();
697 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
698 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
699 encoder.stdOut( "", false );
700 wChannel.close();
701
702 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
703
704 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
705 StandardOutErrEventAssertionListener listener =
706 new StandardOutErrEventAssertionListener( NORMAL_RUN, "", false );
707 notifier.setStdOutListener( listener );
708
709 EH eventHandler = new EH();
710 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
711 ConsoleLogger logger = mock( ConsoleLogger.class );
712 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
713 when( arguments.getConsoleLogger() ).thenReturn( logger );
714 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
715 {
716 t.start();
717 notifier.notifyEvent( eventHandler.pullEvent() );
718 }
719
720 assertThat( listener.called.get() )
721 .isTrue();
722 }
723
724 @Test
725 public void testStdOutStreamPrintWithNull() throws Exception
726 {
727 final Stream out = Stream.newStream();
728 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
729 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
730 encoder.stdOut( null, false );
731 wChannel.close();
732
733 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
734
735 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
736 StandardOutErrEventAssertionListener listener =
737 new StandardOutErrEventAssertionListener( NORMAL_RUN, null, false );
738 notifier.setStdOutListener( listener );
739
740 EH eventHandler = new EH();
741 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
742 ConsoleLogger logger = mock( ConsoleLogger.class );
743 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
744 when( arguments.getConsoleLogger() ).thenReturn( logger );
745 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
746 {
747 t.start();
748 notifier.notifyEvent( eventHandler.pullEvent() );
749 }
750
751 assertThat( listener.called.get() )
752 .isTrue();
753 }
754
755 @Test
756 public void testStdOutStreamPrintln() throws Exception
757 {
758 final Stream out = Stream.newStream();
759 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
760 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
761 encoder.stdOut( "", true );
762 wChannel.close();
763
764 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
765
766 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
767 StandardOutErrEventAssertionListener listener =
768 new StandardOutErrEventAssertionListener( NORMAL_RUN, "", true );
769 notifier.setStdOutListener( listener );
770
771 EH eventHandler = new EH();
772 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
773 ConsoleLogger logger = mock( ConsoleLogger.class );
774 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
775 when( arguments.getConsoleLogger() ).thenReturn( logger );
776 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
777 {
778 t.start();
779 notifier.notifyEvent( eventHandler.pullEvent() );
780 }
781
782 assertThat( listener.called.get() )
783 .isTrue();
784 }
785
786 @Test
787 public void testStdOutStreamPrintlnWithNull() throws Exception
788 {
789 final Stream out = Stream.newStream();
790 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
791 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
792 encoder.stdOut( null, true );
793 wChannel.close();
794
795 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
796
797 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
798 StandardOutErrEventAssertionListener listener =
799 new StandardOutErrEventAssertionListener( NORMAL_RUN, null, true );
800 notifier.setStdOutListener( listener );
801
802 EH eventHandler = new EH();
803 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
804 ConsoleLogger logger = mock( ConsoleLogger.class );
805 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
806 when( arguments.getConsoleLogger() ).thenReturn( logger );
807 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
808 {
809 t.start();
810 notifier.notifyEvent( eventHandler.pullEvent() );
811 }
812
813 assertThat( listener.called.get() )
814 .isTrue();
815 }
816
817 @Test
818 public void testStdErrStream() throws Exception
819 {
820 final Stream out = Stream.newStream();
821 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
822 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
823 encoder.stdErr( "msg", false );
824 wChannel.close();
825
826 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
827
828 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
829 StandardOutErrEventAssertionListener listener =
830 new StandardOutErrEventAssertionListener( NORMAL_RUN, "msg", false );
831 notifier.setStdErrListener( listener );
832
833 EH eventHandler = new EH();
834 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
835 ConsoleLogger logger = mock( ConsoleLogger.class );
836 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
837 when( arguments.getConsoleLogger() ).thenReturn( logger );
838 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
839 {
840 t.start();
841 notifier.notifyEvent( eventHandler.pullEvent() );
842 }
843
844 assertThat( listener.called.get() )
845 .isTrue();
846 }
847
848 @Test
849 public void shouldCountSameNumberOfSystemProperties() throws Exception
850 {
851 final Stream out = Stream.newStream();
852 WritableBufferedByteChannel wChannel = newBufferedChannel( out );
853 LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
854 encoder.sendSystemProperties( ObjectUtils.systemProps() );
855 wChannel.close();
856
857 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
858
859 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
860 PropertyEventAssertionListener listener = new PropertyEventAssertionListener();
861 notifier.setSystemPropertiesListener( listener );
862
863 EH eventHandler = new EH();
864 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
865 ConsoleLogger logger = mock( ConsoleLogger.class );
866 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
867 when( arguments.getConsoleLogger() ).thenReturn( logger );
868 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
869 {
870 t.start();
871 notifier.notifyEvent( eventHandler.pullEvent() );
872 }
873
874 assertThat( listener.called.get() )
875 .isTrue();
876 }
877
878 @Test
879 public void shouldHandleErrorAfterNullLine()
880 {
881 ForkedProcessEventNotifier decoder = new ForkedProcessEventNotifier();
882 decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
883 rule.expect( NullPointerException.class );
884 decoder.notifyEvent( null );
885 }
886
887 @Test
888 public void shouldHandleErrorAfterUnknownOperation() throws Exception
889 {
890 String cmd = ":maven-surefire-event:abnormal-run:-:\n";
891
892 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( cmd.getBytes() ) );
893
894 EH eventHandler = new EH();
895 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
896 ConsoleLogger logger = mock( ConsoleLogger.class );
897 when( logger.isDebugEnabled() ).thenReturn( true );
898 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
899 when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
900 when( arguments.getConsoleLogger() ).thenReturn( logger );
901 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
902 {
903 t.start();
904 countdown.awaitClosed();
905 }
906
907 ArgumentCaptor<String> dumpLine = ArgumentCaptor.forClass( String.class );
908 verify( logger, times( 2 ) ).debug( dumpLine.capture() );
909 assertThat( dumpLine.getAllValues() )
910 .hasSize( 2 )
911 .contains( ":maven-surefire-event:abnormal-run:", atIndex( 0 ) )
912 .contains( "-:", atIndex( 1 ) );
913
914 ArgumentCaptor<String> dumpText = ArgumentCaptor.forClass( String.class );
915 verify( arguments, times( 2 ) ).dumpStreamText( dumpText.capture() );
916 String dump = "Corrupted STDOUT by directly writing to native stream in forked JVM 0.";
917 assertThat( dumpText.getAllValues() )
918 .hasSize( 2 )
919 .contains( format( dump + " Stream '%s'.", ":maven-surefire-event:abnormal-run:" ), atIndex( 0 ) )
920 .contains( format( dump + " Stream '%s'.", "-:" ), atIndex( 1 ) );
921
922 ArgumentCaptor<String> warning = ArgumentCaptor.forClass( String.class );
923 verify( arguments, times( 2 ) ).logWarningAtEnd( warning.capture() );
924 dump += " See FAQ web page and the dump file ";
925 assertThat( warning.getAllValues() )
926 .hasSize( 2 );
927 assertThat( warning.getAllValues().get( 0 ) )
928 .startsWith( dump );
929 assertThat( warning.getAllValues().get( 1 ) )
930 .startsWith( dump );
931 }
932
933 @Test
934 public void shouldHandleExit() throws Exception
935 {
936 final Stream out = Stream.newStream();
937 LegacyMasterProcessChannelEncoder encoder =
938 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
939
940 StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
941 when( stackTraceWriter.getThrowable() ).thenReturn( new SafeThrowable( "1" ) );
942 when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "2" );
943 when( stackTraceWriter.writeTraceToString() ).thenReturn( "3" );
944 when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
945 encoder.sendExitError( stackTraceWriter, false );
946
947 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
948
949 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
950 ProcessExitErrorListener listener = new ProcessExitErrorListener();
951 notifier.setExitErrorEventListener( listener );
952
953 EH eventHandler = new EH();
954 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
955 ConsoleLogger logger = mock( ConsoleLogger.class );
956 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
957 when( arguments.getConsoleLogger() ).thenReturn( logger );
958 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
959 {
960 t.start();
961 notifier.notifyEvent( eventHandler.pullEvent() );
962 }
963
964 assertThat( listener.called.get() )
965 .isTrue();
966 }
967 }
968
969
970
971
972 @RunWith( Theories.class )
973 public static class ReportEntryTest
974 {
975 @DataPoints( value = "operation" )
976 @SuppressWarnings( "checkstyle:visibilitymodifier" )
977 public static String[][] operations = { { "testSetStarting", "setTestSetStartingListener" },
978 { "testSetCompleted", "setTestSetCompletedListener" },
979 { "testStarting", "setTestStartingListener" },
980 { "testSucceeded", "setTestSucceededListener" },
981 { "testFailed", "setTestFailedListener" },
982 { "testSkipped", "setTestSkippedListener" },
983 { "testError", "setTestErrorListener" },
984 { "testAssumptionFailure", "setTestAssumptionFailureListener" }
985 };
986
987 @DataPoints( value = "reportedMessage" )
988 @SuppressWarnings( "checkstyle:visibilitymodifier" )
989 public static String[] reportedMessage = { null, "skipped test" };
990
991 @DataPoints( value = "elapsed" )
992 @SuppressWarnings( { "checkstyle:visibilitymodifier", "checkstyle:magicnumber" } )
993 public static Integer[] elapsed = { null, 102 };
994
995 @DataPoints( value = "trim" )
996 @SuppressWarnings( "checkstyle:visibilitymodifier" )
997 public static boolean[] trim = { false, true };
998
999 @DataPoints( value = "msg" )
1000 @SuppressWarnings( "checkstyle:visibilitymodifier" )
1001 public static boolean[] msg = { false, true };
1002
1003 @DataPoints( value = "smart" )
1004 @SuppressWarnings( "checkstyle:visibilitymodifier" )
1005 public static boolean[] smart = { false, true };
1006
1007 @DataPoints( value = "trace" )
1008 @SuppressWarnings( "checkstyle:visibilitymodifier" )
1009 public static boolean[] trace = { false, true };
1010
1011 @Theory
1012 public void testReportEntryOperations( @FromDataPoints( "operation" ) String[] operation,
1013 @FromDataPoints( "reportedMessage" ) String reportedMessage,
1014 @FromDataPoints( "elapsed" ) Integer elapsed,
1015 @FromDataPoints( "trim" ) boolean trim,
1016 @FromDataPoints( "msg" ) boolean msg,
1017 @FromDataPoints( "smart" ) boolean smart,
1018 @FromDataPoints( "trace" ) boolean trace )
1019 throws Exception
1020 {
1021 String exceptionMessage = msg ? "msg" : null;
1022 String smartStackTrace = smart ? "MyTest:86 >> Error" : null;
1023 String exceptionStackTrace =
1024 trace ? ( trim ? "trace line 1\ntrace line 2" : "Exception: msg\ntrace line 1\ntrace line 2" )
1025 : null;
1026
1027 StackTraceWriter stackTraceWriter = null;
1028 if ( exceptionStackTrace != null )
1029 {
1030 SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
1031 stackTraceWriter = mock( StackTraceWriter.class );
1032 when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
1033 when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
1034 when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
1035 when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
1036 }
1037
1038 ReportEntry reportEntry = mock( ReportEntry.class );
1039 when( reportEntry.getElapsed() ).thenReturn( elapsed );
1040 when( reportEntry.getGroup() ).thenReturn( "this group" );
1041 when( reportEntry.getMessage() ).thenReturn( reportedMessage );
1042 when( reportEntry.getName() ).thenReturn( "my test" );
1043 when( reportEntry.getName() ).thenReturn( "display name of test" );
1044 when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
1045 when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
1046 when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
1047 when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
1048
1049 final Stream out = Stream.newStream();
1050
1051 LegacyMasterProcessChannelEncoder encoder =
1052 new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
1053
1054 LegacyMasterProcessChannelEncoder.class.getMethod( operation[0], ReportEntry.class, boolean.class )
1055 .invoke( encoder, reportEntry, trim );
1056
1057 ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
1058
1059 ForkedProcessEventNotifier.class.getMethod( operation[1], ForkedProcessReportEventListener.class )
1060 .invoke( notifier, new ReportEventAssertionListener( reportEntry, stackTraceWriter != null ) );
1061
1062 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
1063
1064 EH eventHandler = new EH();
1065 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
1066 ConsoleLogger logger = mock( ConsoleLogger.class );
1067 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
1068 when( arguments.getConsoleLogger() ).thenReturn( logger );
1069 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
1070 {
1071 t.start();
1072 notifier.notifyEvent( eventHandler.pullEvent() );
1073 }
1074 }
1075 }
1076
1077 private static class ProcessExitErrorListener implements ForkedProcessExitErrorListener
1078 {
1079 final AtomicBoolean called = new AtomicBoolean();
1080
1081 @Override
1082 public void handle( StackTraceWriter stackTrace )
1083 {
1084 called.set( true );
1085 assertThat( stackTrace.getThrowable().getMessage() ).isEqualTo( "1" );
1086 assertThat( stackTrace.smartTrimmedStackTrace() ).isEqualTo( "2" );
1087 assertThat( stackTrace.writeTraceToString() ).isEqualTo( "3" );
1088 }
1089 }
1090
1091 private static class PropertyEventAssertionListener implements ForkedProcessPropertyEventListener
1092 {
1093 final AtomicBoolean called = new AtomicBoolean();
1094 private final Map<?, ?> sysProps = System.getProperties();
1095 private final AtomicInteger counter = new AtomicInteger();
1096
1097 public void handle( RunMode runMode, String key, String value )
1098 {
1099 called.set( true );
1100 counter.incrementAndGet();
1101 assertThat( runMode ).isEqualTo( NORMAL_RUN );
1102 assertTrue( sysProps.containsKey( key ) );
1103 assertThat( sysProps.get( key ) ).isEqualTo( value );
1104 }
1105 }
1106
1107 private static class EventAssertionListener implements ForkedProcessEventListener
1108 {
1109 final AtomicBoolean called = new AtomicBoolean();
1110
1111 public void handle()
1112 {
1113 called.set( true );
1114 }
1115 }
1116
1117 private static class StringEventAssertionListener implements ForkedProcessStringEventListener
1118 {
1119 final AtomicBoolean called = new AtomicBoolean();
1120 private final String msg;
1121
1122 StringEventAssertionListener( String msg )
1123 {
1124 this.msg = msg;
1125 }
1126
1127 public void handle( String msg )
1128 {
1129 called.set( true );
1130 assertThat( msg )
1131 .isEqualTo( this.msg );
1132 }
1133 }
1134
1135 private static class StackTraceEventListener implements ForkedProcessStackTraceEventListener
1136 {
1137 final AtomicBoolean called = new AtomicBoolean();
1138 private final String msg;
1139 private final String smartStackTrace;
1140 private final String stackTrace;
1141
1142 StackTraceEventListener( String msg, String smartStackTrace, String stackTrace )
1143 {
1144 this.msg = msg;
1145 this.smartStackTrace = smartStackTrace;
1146 this.stackTrace = stackTrace;
1147 }
1148
1149 @Override
1150 public void handle( @Nonnull StackTraceWriter stackTrace )
1151 {
1152 called.set( true );
1153
1154 assertThat( stackTrace.getThrowable().getMessage() )
1155 .isEqualTo( msg );
1156
1157 assertThat( stackTrace.smartTrimmedStackTrace() )
1158 .isEqualTo( smartStackTrace );
1159
1160 assertThat( stackTrace.writeTraceToString() )
1161 .isEqualTo( this.stackTrace );
1162 }
1163 }
1164
1165 private static class StandardOutErrEventAssertionListener implements ForkedProcessStandardOutErrEventListener
1166 {
1167 final AtomicBoolean called = new AtomicBoolean();
1168 private final RunMode runMode;
1169 private final String output;
1170 private final boolean newLine;
1171
1172 StandardOutErrEventAssertionListener( RunMode runMode, String output, boolean newLine )
1173 {
1174 this.runMode = runMode;
1175 this.output = output;
1176 this.newLine = newLine;
1177 }
1178
1179 public void handle( RunMode runMode, String output, boolean newLine )
1180 {
1181 called.set( true );
1182
1183 assertThat( runMode )
1184 .isEqualTo( this.runMode );
1185
1186 assertThat( output )
1187 .isEqualTo( this.output );
1188
1189 assertThat( newLine )
1190 .isEqualTo( this.newLine );
1191 }
1192 }
1193
1194 private static class ReportEventAssertionListener implements ForkedProcessReportEventListener<ReportEntry>
1195 {
1196 final AtomicBoolean called = new AtomicBoolean();
1197 private final ReportEntry reportEntry;
1198 private final boolean hasStackTrace;
1199
1200 ReportEventAssertionListener( ReportEntry reportEntry, boolean hasStackTrace )
1201 {
1202 this.reportEntry = reportEntry;
1203 this.hasStackTrace = hasStackTrace;
1204 }
1205
1206 public void handle( RunMode runMode, ReportEntry reportEntry )
1207 {
1208 called.set( true );
1209 assertThat( reportEntry.getSourceName() ).isEqualTo( this.reportEntry.getSourceName() );
1210 assertThat( reportEntry.getSourceText() ).isEqualTo( this.reportEntry.getSourceText() );
1211 assertThat( reportEntry.getName() ).isEqualTo( this.reportEntry.getName() );
1212 assertThat( reportEntry.getNameText() ).isEqualTo( this.reportEntry.getNameText() );
1213 assertThat( reportEntry.getGroup() ).isEqualTo( this.reportEntry.getGroup() );
1214 assertThat( reportEntry.getMessage() ).isEqualTo( this.reportEntry.getMessage() );
1215 assertThat( reportEntry.getElapsed() ).isEqualTo( this.reportEntry.getElapsed() );
1216 if ( reportEntry.getStackTraceWriter() == null )
1217 {
1218 assertThat( hasStackTrace ).isFalse();
1219 assertThat( this.reportEntry.getStackTraceWriter() ).isNull();
1220 }
1221 else
1222 {
1223 assertThat( hasStackTrace ).isTrue();
1224 assertThat( this.reportEntry.getStackTraceWriter() ).isNotNull();
1225
1226 assertThat( reportEntry.getStackTraceWriter().getThrowable().getMessage() )
1227 .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getMessage() );
1228
1229 assertThat( reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() )
1230 .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() );
1231
1232 assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
1233 .isEqualTo( this.reportEntry.getStackTraceWriter().smartTrimmedStackTrace() );
1234 }
1235 }
1236 }
1237
1238 private static class Stream extends PrintStream
1239 {
1240 private final ByteArrayOutputStream out;
1241
1242 Stream( ByteArrayOutputStream out )
1243 {
1244 super( out, true );
1245 this.out = out;
1246 }
1247
1248 byte[] toByteArray()
1249 {
1250 return out.toByteArray();
1251 }
1252
1253 LineNumberReader newReader( Charset streamCharset )
1254 {
1255 return new LineNumberReader( new StringReader( new String( toByteArray(), streamCharset ) ) );
1256 }
1257
1258 static Stream newStream()
1259 {
1260 return new Stream( new ByteArrayOutputStream() );
1261 }
1262 }
1263
1264 private static byte[] toArray( ByteBuffer buffer )
1265 {
1266 return copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
1267 }
1268
1269 private static class EH implements EventHandler<Event>
1270 {
1271 private final BlockingQueue<Event> cache = new LinkedTransferQueue<>();
1272
1273 Event pullEvent() throws InterruptedException
1274 {
1275 return cache.poll( 1, TimeUnit.MINUTES );
1276 }
1277
1278 @Override
1279 public void handleEvent( @Nonnull Event event )
1280 {
1281 cache.add( event );
1282 }
1283 }
1284 }