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