1 package org.apache.maven.plugin.surefire.booterclient;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import junit.framework.TestCase;
23 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
24 import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
25 import org.apache.maven.plugin.surefire.extensions.EventConsumerThread;
26 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
27 import org.apache.maven.surefire.api.booter.ForkingRunListener;
28 import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder;
29 import org.apache.maven.surefire.api.event.Event;
30 import org.apache.maven.surefire.extensions.EventHandler;
31 import org.apache.maven.surefire.extensions.ForkNodeArguments;
32 import org.apache.maven.surefire.extensions.util.CountdownCloseable;
33 import org.apache.maven.surefire.api.report.CategorizedReportEntry;
34 import org.apache.maven.surefire.api.report.ConsoleOutputReceiver;
35 import org.apache.maven.surefire.api.report.LegacyPojoStackTraceWriter;
36 import org.apache.maven.surefire.api.report.ReportEntry;
37 import org.apache.maven.surefire.api.report.ReporterException;
38 import org.apache.maven.surefire.api.report.RunListener;
39 import org.apache.maven.surefire.api.report.SimpleReportEntry;
40 import org.apache.maven.surefire.api.report.StackTraceWriter;
41 import org.apache.maven.surefire.api.report.TestSetReportEntry;
42 import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
43
44 import javax.annotation.Nonnull;
45 import java.io.ByteArrayInputStream;
46 import java.io.ByteArrayOutputStream;
47 import java.io.Closeable;
48 import java.io.PrintStream;
49 import java.nio.channels.ReadableByteChannel;
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.concurrent.BlockingQueue;
55 import java.util.concurrent.LinkedBlockingQueue;
56 import java.util.concurrent.TimeUnit;
57
58 import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
59 import static org.apache.maven.surefire.api.util.internal.Channels.newChannel;
60 import static org.mockito.Mockito.mock;
61 import static org.mockito.Mockito.when;
62
63
64
65
66 @SuppressWarnings( "checkstyle:magicnumber" )
67 public class ForkingRunListenerTest
68 extends TestCase
69 {
70 private final ByteArrayOutputStream content, anotherContent;
71
72 private final PrintStream printStream, anotherPrintStream;
73
74 public ForkingRunListenerTest()
75 {
76 content = new ByteArrayOutputStream();
77 printStream = new PrintStream( content );
78
79 anotherContent = new ByteArrayOutputStream();
80 anotherPrintStream = new PrintStream( anotherContent );
81 }
82
83 private void reset()
84 {
85 printStream.flush();
86 content.reset();
87 }
88
89 public void testSetStarting() throws Exception
90 {
91 final StandardTestRun standardTestRun = new StandardTestRun();
92 TestSetReportEntry expected = createDefaultReportEntry();
93 standardTestRun.run().testSetStarting( expected );
94 standardTestRun.assertExpected( MockReporter.SET_STARTING, expected );
95 }
96
97 public void testSetCompleted() throws Exception
98 {
99 final StandardTestRun standardTestRun = new StandardTestRun();
100 TestSetReportEntry expected = createDefaultReportEntry();
101 standardTestRun.run().testSetCompleted( expected );
102 standardTestRun.assertExpected( MockReporter.SET_COMPLETED, expected );
103 }
104
105 public void testStarting() throws Exception
106 {
107 final StandardTestRun standardTestRun = new StandardTestRun();
108 ReportEntry expected = createDefaultReportEntry();
109 standardTestRun.run().testStarting( expected );
110 standardTestRun.assertExpected( MockReporter.TEST_STARTING, expected );
111 }
112
113 public void testSucceeded() throws Exception
114 {
115 final StandardTestRun standardTestRun = new StandardTestRun();
116 ReportEntry expected = createDefaultReportEntry();
117 standardTestRun.run().testSucceeded( expected );
118 standardTestRun.assertExpected( MockReporter.TEST_SUCCEEDED, expected );
119 }
120
121 public void testFailed() throws Exception
122 {
123 final StandardTestRun standardTestRun = new StandardTestRun();
124 ReportEntry expected = createReportEntryWithStackTrace();
125 standardTestRun.run().testFailed( expected );
126 standardTestRun.assertExpected( MockReporter.TEST_FAILED, expected );
127 }
128
129 public void testFailedWithCommaInMessage() throws Exception
130 {
131 final StandardTestRun standardTestRun = new StandardTestRun();
132 ReportEntry expected = createReportEntryWithSpecialMessage( "We, the people" );
133 standardTestRun.run().testFailed( expected );
134 standardTestRun.assertExpected( MockReporter.TEST_FAILED, expected );
135 }
136
137 public void testFailedWithUnicodeEscapeInMessage() throws Exception
138 {
139 final StandardTestRun standardTestRun = new StandardTestRun();
140 ReportEntry expected = createReportEntryWithSpecialMessage( "We, \\u0177 people" );
141 standardTestRun.run().testFailed( expected );
142 standardTestRun.assertExpected( MockReporter.TEST_FAILED, expected );
143 }
144
145 public void testFailure() throws Exception
146 {
147 final StandardTestRun standardTestRun = new StandardTestRun();
148 ReportEntry expected = createDefaultReportEntry();
149 standardTestRun.run().testError( expected );
150 standardTestRun.assertExpected( MockReporter.TEST_ERROR, expected );
151 }
152
153 public void testSkipped() throws Exception
154 {
155 final StandardTestRun standardTestRun = new StandardTestRun();
156 ReportEntry expected = createDefaultReportEntry();
157 standardTestRun.run().testSkipped( expected );
158 standardTestRun.assertExpected( MockReporter.TEST_SKIPPED, expected );
159 }
160
161 public void testAssumptionFailure() throws Exception
162 {
163 final StandardTestRun standardTestRun = new StandardTestRun();
164 ReportEntry expected = createDefaultReportEntry();
165 standardTestRun.run().testAssumptionFailure( expected );
166 standardTestRun.assertExpected( MockReporter.TEST_ASSUMPTION_FAIL, expected );
167 }
168
169 public void testConsole() throws Exception
170 {
171 final StandardTestRun standardTestRun = new StandardTestRun();
172 ConsoleLogger directConsoleReporter = (ConsoleLogger) standardTestRun.run();
173 directConsoleReporter.info( "HeyYou" );
174 standardTestRun.assertExpected( MockReporter.CONSOLE_INFO, "HeyYou" );
175 }
176
177 public void testConsoleOutput() throws Exception
178 {
179 final StandardTestRun standardTestRun = new StandardTestRun();
180 ConsoleOutputReceiver directConsoleReporter = (ConsoleOutputReceiver) standardTestRun.run();
181 directConsoleReporter.writeTestOutput( "HeyYou", false, true );
182 standardTestRun.assertExpected( MockReporter.STDOUT, "HeyYou" );
183 }
184
185 public void testSystemProperties() throws Exception
186 {
187 StandardTestRun standardTestRun = new StandardTestRun();
188 standardTestRun.run();
189
190 reset();
191 createForkingRunListener();
192
193 TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
194 ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
195
196 byte[] cmd = ":maven-surefire-event:sys-prop:normal-run:UTF-8:azE=:djE=:\n".getBytes();
197 for ( Event e : streamToEvent( cmd ) )
198 {
199 forkStreamClient.handleEvent( e );
200 }
201 cmd = "\n:maven-surefire-event:sys-prop:normal-run:UTF-8:azI=:djI=:\n".getBytes();
202 for ( Event e : streamToEvent( cmd ) )
203 {
204 forkStreamClient.handleEvent( e );
205 }
206
207 assertTrue( forkStreamClient.getTestVmSystemProperties().size() == 2 );
208 assertTrue( forkStreamClient.getTestVmSystemProperties().containsKey( "k1" ) );
209 assertTrue( forkStreamClient.getTestVmSystemProperties().containsKey( "k2" ) );
210 }
211
212 public void testMultipleEntries() throws Exception
213 {
214 StandardTestRun standardTestRun = new StandardTestRun();
215 standardTestRun.run();
216
217 reset();
218 RunListener forkingReporter = createForkingRunListener();
219
220 TestSetReportEntry reportEntry = createDefaultReportEntry();
221 forkingReporter.testSetStarting( reportEntry );
222 forkingReporter.testStarting( reportEntry );
223 forkingReporter.testSucceeded( reportEntry );
224 forkingReporter.testSetCompleted( reportEntry );
225
226 TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
227 ForkClient forkStreamClient =
228 new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
229
230 for ( Event e : streamToEvent( content.toByteArray() ) )
231 {
232 forkStreamClient.handleEvent( e );
233 }
234
235 final MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
236 final List<String> events = reporter.getEvents();
237 assertEquals( MockReporter.SET_STARTING, events.get( 0 ) );
238 assertEquals( MockReporter.TEST_STARTING, events.get( 1 ) );
239 assertEquals( MockReporter.TEST_SUCCEEDED, events.get( 2 ) );
240 assertEquals( MockReporter.SET_COMPLETED, events.get( 3 ) );
241 }
242
243 public void test2DifferentChannels()
244 throws Exception
245 {
246 reset();
247 ReportEntry expected = createDefaultReportEntry();
248 SimpleReportEntry secondExpected = createAnotherDefaultReportEntry();
249
250 new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newBufferedChannel( printStream ) ), false )
251 .testStarting( expected );
252
253 new ForkingRunListener(
254 new LegacyMasterProcessChannelEncoder( newBufferedChannel( anotherPrintStream ) ), false )
255 .testSkipped( secondExpected );
256
257 TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
258 NotifiableTestStream notifiableTestStream = new MockNotifiableTestStream();
259
260 ForkClient forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, 1 );
261 for ( Event e : streamToEvent( content.toByteArray() ) )
262 {
263 forkStreamClient.handleEvent( e );
264 }
265
266 MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
267 assertEquals( MockReporter.TEST_STARTING, reporter.getFirstEvent() );
268 assertEquals( expected, reporter.getFirstData() );
269 assertEquals( 1, reporter.getEvents().size() );
270
271 forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, 2 );
272 for ( Event e : streamToEvent( anotherContent.toByteArray() ) )
273 {
274 forkStreamClient.handleEvent( e );
275 }
276 MockReporter reporter2 = (MockReporter) forkStreamClient.getReporter();
277 assertEquals( MockReporter.TEST_SKIPPED, reporter2.getFirstEvent() );
278 assertEquals( secondExpected, reporter2.getFirstData() );
279 assertEquals( 1, reporter2.getEvents().size() );
280 }
281
282 private static List<Event> streamToEvent( byte[] stream ) throws Exception
283 {
284 List<Event> events = new ArrayList<>();
285 EH handler = new EH();
286 CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
287 ConsoleLogger logger = mock( ConsoleLogger.class );
288 ForkNodeArguments arguments = mock( ForkNodeArguments.class );
289 when( arguments.getConsoleLogger() ).thenReturn( logger );
290 ReadableByteChannel channel = newChannel( new ByteArrayInputStream( stream ) );
291 try ( EventConsumerThread t = new EventConsumerThread( "t", channel, handler, countdown, arguments ) )
292 {
293 t.start();
294 countdown.awaitClosed();
295 for ( int i = 0, size = handler.countEventsInCache(); i < size; i++ )
296 {
297 events.add( handler.pullEvent() );
298 }
299 assertEquals( 0, handler.countEventsInCache() );
300 return events;
301 }
302 }
303
304 private static class EH implements EventHandler<Event>
305 {
306 private final BlockingQueue<Event> cache = new LinkedBlockingQueue<>();
307
308 Event pullEvent() throws InterruptedException
309 {
310 return cache.poll( 1, TimeUnit.MINUTES );
311 }
312
313 int countEventsInCache()
314 {
315 return cache.size();
316 }
317
318 @Override
319 public void handleEvent( @Nonnull Event event )
320 {
321 cache.add( event );
322 }
323 }
324
325
326
327 private SimpleReportEntry createDefaultReportEntry( Map<String, String> sysProps )
328 {
329 return new SimpleReportEntry( "com.abc.TestClass", null, "testMethod", null, null, 22, sysProps );
330 }
331
332 private SimpleReportEntry createDefaultReportEntry()
333 {
334 return createDefaultReportEntry( Collections.<String, String>emptyMap() );
335 }
336
337 private SimpleReportEntry createAnotherDefaultReportEntry()
338 {
339 return new SimpleReportEntry( "com.abc.AnotherTestClass", null, "testAnotherMethod", null, 42 );
340 }
341
342 private SimpleReportEntry createReportEntryWithStackTrace()
343 {
344 try
345 {
346 throw new RuntimeException();
347 }
348 catch ( RuntimeException e )
349 {
350 StackTraceWriter stackTraceWriter =
351 new LegacyPojoStackTraceWriter( "org.apache.tests.TestClass", "testMethod11", e );
352 return new CategorizedReportEntry( "com.abc.TestClass", "testMethod", "aGroup", stackTraceWriter, 77 );
353 }
354 }
355
356 private SimpleReportEntry createReportEntryWithSpecialMessage( String message )
357 {
358 try
359 {
360 throw new RuntimeException( message );
361 }
362 catch ( RuntimeException e )
363 {
364 StackTraceWriter stackTraceWriter =
365 new LegacyPojoStackTraceWriter( "org.apache.tests.TestClass", "testMethod11", e );
366 return new CategorizedReportEntry( "com.abc.TestClass", "testMethod", "aGroup", stackTraceWriter, 77 );
367 }
368 }
369
370 private RunListener createForkingRunListener()
371 {
372 WritableBufferedByteChannel channel = (WritableBufferedByteChannel) newChannel( printStream );
373 return new ForkingRunListener( new LegacyMasterProcessChannelEncoder( channel ), false );
374 }
375
376 private class StandardTestRun
377 {
378 private MockReporter reporter;
379
380 public RunListener run()
381 throws ReporterException
382 {
383 reset();
384 return createForkingRunListener();
385 }
386
387 public void clientReceiveContent() throws Exception
388 {
389 TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
390 ForkClient handler = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
391 for ( Event e : streamToEvent( content.toByteArray() ) )
392 {
393 handler.handleEvent( e );
394 }
395 reporter = (MockReporter) handler.getReporter();
396 }
397
398 public String getFirstEvent()
399 {
400 return reporter.getEvents().get( 0 );
401 }
402
403 public ReportEntry getFirstData()
404 {
405 return (ReportEntry) reporter.getData().get( 0 );
406 }
407
408 private void assertExpected( String actionCode, ReportEntry expected ) throws Exception
409 {
410 clientReceiveContent();
411 assertEquals( actionCode, getFirstEvent() );
412 final ReportEntry firstData = getFirstData();
413 assertEquals( expected.getSourceName(), firstData.getSourceName() );
414 assertEquals( expected.getName(), firstData.getName() );
415
416 assertEquals( expected.getElapsed(), firstData.getElapsed() );
417 assertEquals( expected.getGroup(), firstData.getGroup() );
418 if ( expected.getStackTraceWriter() != null )
419 {
420
421 assertEquals( expected.getStackTraceWriter().getThrowable().getLocalizedMessage(),
422 firstData.getStackTraceWriter().getThrowable().getLocalizedMessage() );
423 assertEquals( expected.getStackTraceWriter().writeTraceToString(),
424 firstData.getStackTraceWriter().writeTraceToString() );
425 }
426 }
427
428 private void assertExpected( String actionCode, String expected ) throws Exception
429 {
430 clientReceiveContent();
431 assertEquals( actionCode, getFirstEvent() );
432 final String firstData = (String) reporter.getData().get( 0 );
433 assertEquals( expected, firstData );
434 }
435
436 }
437 }