View Javadoc

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 }