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 org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
23 import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
24 import org.apache.maven.surefire.api.booter.MasterProcessChannelDecoder;
25 import org.apache.maven.surefire.api.booter.Shutdown;
26 import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelDecoder;
27 import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder;
28 import org.apache.maven.surefire.api.testset.TestSetFailedException;
29 import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
30 import org.junit.After;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34
35 import java.io.ByteArrayOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.PrintStream;
39 import java.util.Iterator;
40 import java.util.NoSuchElementException;
41 import java.util.concurrent.BlockingQueue;
42 import java.util.concurrent.CountDownLatch;
43 import java.util.concurrent.ExecutionException;
44 import java.util.concurrent.FutureTask;
45 import java.util.concurrent.LinkedBlockingQueue;
46 import java.util.concurrent.TimeUnit;
47
48 import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
49 import static org.apache.maven.surefire.api.util.internal.Channels.newChannel;
50 import static org.fest.assertions.Assertions.assertThat;
51 import static org.hamcrest.MatcherAssert.assertThat;
52 import static org.hamcrest.Matchers.is;
53 import static org.junit.Assert.assertFalse;
54 import static org.junit.Assert.assertTrue;
55 import static org.junit.Assert.fail;
56
57
58
59
60
61
62
63 @RunWith( NewClassLoaderRunner.class )
64 public class CommandReaderTest
65 {
66 private static final long DELAY = 200L;
67 private static final long TEST_TIMEOUT = 15_000L;
68
69 private final BlockingQueue<Byte> blockingStream = new LinkedBlockingQueue<>();
70 private CommandReader reader;
71
72 static class A
73 {
74 }
75
76 static class B
77 {
78 }
79
80 static class C
81 {
82 }
83
84 static class D
85 {
86 }
87
88 @Before
89 public void init()
90 {
91
92 Thread.interrupted();
93 InputStream realInputStream = new SystemInputStream();
94 addTestToPipeline( getClass().getName() );
95 ConsoleLogger logger = new NullConsoleLogger();
96 MasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( realInputStream ) );
97 reader = new CommandReader( decoder, Shutdown.DEFAULT, logger );
98 }
99
100 @After
101 public void deinit()
102 {
103 reader.stop();
104 }
105
106 @Test
107 public void readJustOneClass()
108 {
109 Iterator<String> it = reader.getIterableClasses( new LegacyMasterProcessChannelEncoder( nul() ) ).iterator();
110 assertTrue( it.hasNext() );
111 assertThat( it.next(), is( getClass().getName() ) );
112 reader.stop();
113 assertFalse( it.hasNext() );
114 try
115 {
116 it.next();
117 fail();
118 }
119 catch ( NoSuchElementException e )
120 {
121
122 }
123 }
124
125 @Test
126 public void manyClasses()
127 {
128 Iterator<String> it1 = reader.getIterableClasses( new LegacyMasterProcessChannelEncoder( nul() ) ).iterator();
129 assertThat( it1.next(), is( getClass().getName() ) );
130 addTestToPipeline( A.class.getName() );
131 assertThat( it1.next(), is( A.class.getName() ) );
132 addTestToPipeline( B.class.getName() );
133 assertThat( it1.next(), is( B.class.getName() ) );
134 addTestToPipeline( C.class.getName() );
135 assertThat( it1.next(), is( C.class.getName() ) );
136 addEndOfPipeline();
137 addTestToPipeline( D.class.getName() );
138 assertFalse( it1.hasNext() );
139 }
140
141 @Test
142 public void twoIterators() throws Exception
143 {
144 Iterator<String> it1 = reader.getIterableClasses( new LegacyMasterProcessChannelEncoder( nul() ) ).iterator();
145
146 assertThat( it1.next(), is( getClass().getName() ) );
147 addTestToPipeline( A.class.getName() );
148 assertThat( it1.next(), is( A.class.getName() ) );
149 addTestToPipeline( B.class.getName() );
150
151 TimeUnit.MILLISECONDS.sleep( DELAY );
152
153 Iterator<String> it2 = reader.iterated();
154
155 assertThat( it1.next(), is( B.class.getName() ) );
156 addTestToPipeline( C.class.getName() );
157
158 assertThat( it2.hasNext(), is( true ) );
159 assertThat( it2.next(), is( getClass().getName() ) );
160 assertThat( it2.hasNext(), is( true ) );
161 assertThat( it2.next(), is( A.class.getName() ) );
162 assertThat( it2 ).isEmpty();
163
164 assertThat( it1.next(), is( C.class.getName() ) );
165 addEndOfPipeline();
166 assertThat( it1 ).isEmpty();
167 }
168
169 @Test( expected = NoSuchElementException.class )
170 public void stopBeforeReadInThread() throws Throwable
171 {
172 Runnable runnable = new Runnable()
173 {
174 @Override
175 public void run()
176 {
177 Iterator<String> it =
178 reader.getIterableClasses( new LegacyMasterProcessChannelEncoder( nul() ) ).iterator();
179 assertThat( it.next(), is( CommandReaderTest.class.getName() ) );
180 }
181 };
182 FutureTask<Object> futureTask = new FutureTask<>( runnable, null );
183 Thread t = new Thread( futureTask );
184 reader.stop();
185 t.start();
186 try
187 {
188 futureTask.get();
189 }
190 catch ( ExecutionException e )
191 {
192 throw e.getCause();
193 }
194 }
195
196 @Test
197 public void readTwoClassesInThread() throws Throwable
198 {
199 final CountDownLatch counter = new CountDownLatch( 1 );
200 Runnable runnable = new Runnable()
201 {
202 @Override
203 public void run()
204 {
205 Iterator<String> it =
206 reader.getIterableClasses( new LegacyMasterProcessChannelEncoder( nul() ) ).iterator();
207 assertThat( it.next(), is( CommandReaderTest.class.getName() ) );
208 counter.countDown();
209 assertThat( it.next(), is( Foo.class.getName() ) );
210 }
211 };
212 FutureTask<Object> futureTask = new FutureTask<>( runnable, null );
213 Thread t = new Thread( futureTask );
214 t.start();
215 counter.await();
216 addTestToPipeline( Foo.class.getName() );
217 try
218 {
219 futureTask.get();
220 }
221 catch ( ExecutionException e )
222 {
223 throw e.getCause();
224 }
225 }
226
227 @Test( timeout = TEST_TIMEOUT )
228 public void shouldAwaitReaderUp() throws TestSetFailedException
229 {
230 assertTrue( reader.awaitStarted() );
231 reader.stop();
232 assertFalse( reader.awaitStarted() );
233 }
234
235 private class SystemInputStream extends InputStream
236 {
237 @Override
238 public int read() throws IOException
239 {
240 try
241 {
242 return CommandReaderTest.this.blockingStream.take();
243 }
244 catch ( InterruptedException e )
245 {
246 throw new IOException( e );
247 }
248 }
249 }
250
251 private void addTestToPipeline( String cls )
252 {
253 for ( byte cmdByte : ( ":maven-surefire-command:run-testclass:" + cls + ":" ).getBytes() )
254 {
255 blockingStream.add( cmdByte );
256 }
257 }
258
259 private void addEndOfPipeline()
260 {
261 for ( byte cmdByte : ":maven-surefire-command:testset-finished:".getBytes() )
262 {
263 blockingStream.add( cmdByte );
264 }
265 }
266
267 private static WritableBufferedByteChannel nul()
268 {
269 return newBufferedChannel( new PrintStream( new ByteArrayOutputStream() ) );
270 }
271 }