1 package org.apache.maven.surefire.util;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.PrintStream;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Iterator;
30 import java.util.List;
31 import org.apache.maven.surefire.booter.ForkingRunListener;
32
33 /**
34 * A variant of TestsToRun that is provided with test class names
35 * from an {@link InputStream} (e.g. {@code System.in}). The method
36 * {@link #iterator()} returns an Iterator that blocks on calls to
37 * {@link Iterator#hasNext()} until new classes are available, or no more
38 * classes will be available.
39 *
40 * @author Andreas Gudian
41 */
42 public class LazyTestsToRun
43 extends TestsToRun
44 {
45 private List workQueue = new ArrayList();
46
47 private BufferedReader inputReader;
48
49 private boolean streamClosed = false;
50
51 private ClassLoader testClassLoader;
52
53 private PrintStream originalOutStream;
54
55 /**
56 * C'tor
57 *
58 * @param testSource source to read the tests from
59 * @param testClassLoader class loader to load the test classes
60 * @param originalOutStream the output stream to use when requesting new new tests
61 */
62 public LazyTestsToRun( InputStream testSource, ClassLoader testClassLoader, PrintStream originalOutStream )
63 {
64 super( Collections.emptyList() );
65
66 this.testClassLoader = testClassLoader;
67 this.originalOutStream = originalOutStream;
68
69 inputReader = new BufferedReader( new InputStreamReader( testSource ) );
70 }
71
72 protected void addWorkItem( String className )
73 {
74 synchronized ( workQueue )
75 {
76 workQueue.add( ReflectionUtils.loadClass( testClassLoader, className ) );
77 }
78 }
79
80 protected void requestNextTest()
81 {
82 StringBuffer sb = new StringBuffer();
83 sb.append( (char) ForkingRunListener.BOOTERCODE_NEXT_TEST ).append( ",0,want more!\n" );
84 originalOutStream.print( sb.toString() );
85 }
86
87 private class BlockingIterator
88 implements Iterator
89 {
90 private int lastPos = -1;
91
92 public boolean hasNext()
93 {
94 int nextPos = lastPos + 1;
95 synchronized ( workQueue )
96 {
97 if ( workQueue.size() > nextPos )
98 {
99 return true;
100 }
101 else
102 {
103 if ( needsToWaitForInput( nextPos ) )
104 {
105 requestNextTest();
106
107 String nextClassName;
108 try
109 {
110 nextClassName = inputReader.readLine();
111 }
112 catch ( IOException e )
113 {
114 streamClosed = true;
115 return false;
116 }
117
118 if ( null == nextClassName )
119 {
120 streamClosed = true;
121 }
122 else
123 {
124 addWorkItem( nextClassName );
125 }
126 }
127
128 return ( workQueue.size() > nextPos );
129 }
130 }
131 }
132
133 private boolean needsToWaitForInput( int nextPos )
134 {
135 return workQueue.size() == nextPos && !streamClosed;
136 }
137
138 public Object next()
139 {
140 synchronized ( workQueue )
141 {
142 return workQueue.get( ++lastPos );
143 }
144 }
145
146 public void remove()
147 {
148 throw new UnsupportedOperationException();
149 }
150
151 }
152
153 /* (non-Javadoc)
154 * @see org.apache.maven.surefire.util.TestsToRun#iterator()
155 */
156 public Iterator iterator()
157 {
158 return new BlockingIterator();
159 }
160
161 /* (non-Javadoc)
162 * @see org.apache.maven.surefire.util.TestsToRun#toString()
163 */
164 public String toString()
165 {
166 StringBuffer sb = new StringBuffer( "LazyTestsToRun " );
167 synchronized ( workQueue )
168 {
169 sb.append( "(more items expected: " ).append( !streamClosed ).append( "): " );
170 sb.append( workQueue );
171 }
172
173 return sb.toString();
174 }
175
176 /* (non-Javadoc)
177 * @see org.apache.maven.surefire.util.TestsToRun#allowEagerReading()
178 */
179 public boolean allowEagerReading() {
180 return false;
181 }
182
183 }