View Javadoc

1   package org.apache.maven.surefire.junitcore;
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.util.Collection;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.TreeSet;
26  import java.util.concurrent.Future;
27  import java.util.concurrent.TimeUnit;
28  
29  import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
30  import org.apache.maven.surefire.junitcore.pc.ParallelComputer;
31  import org.apache.maven.surefire.testset.TestSetFailedException;
32  import org.apache.maven.surefire.util.TestsToRun;
33  
34  import org.junit.runner.Computer;
35  import org.junit.runner.Description;
36  import org.junit.runner.JUnitCore;
37  import org.junit.runner.Request;
38  import org.junit.runner.Result;
39  import org.junit.runner.Runner;
40  import org.junit.runner.manipulation.Filter;
41  import org.junit.runner.manipulation.NoTestsRemainException;
42  import org.junit.runner.notification.RunListener;
43  
44  /**
45   * Encapsulates access to JUnitCore
46   *
47   * @author Kristian Rosenvold
48   */
49  
50  class JUnitCoreWrapper
51  {
52      private static class FilteringRequest
53          extends Request
54      {
55          private Runner filteredRunner;
56  
57          public FilteringRequest( Request req, Filter filter )
58          {
59              try
60              {
61                  Runner runner = req.getRunner();
62                  filter.apply( runner );
63                  filteredRunner = runner;
64              }
65              catch ( NoTestsRemainException e )
66              {
67                  filteredRunner = null;
68              }
69          }
70  
71          @Override
72          public Runner getRunner()
73          {
74              return filteredRunner;
75          }
76      }
77  
78      public static void execute( TestsToRun testsToRun, JUnitCoreParameters jUnitCoreParameters,
79                                  List<RunListener> listeners, Filter filter )
80          throws TestSetFailedException
81      {
82          ComputerWrapper computerWrapper = createComputer( jUnitCoreParameters );
83          JUnitCore junitCore = createJUnitCore( listeners );
84          if ( testsToRun.allowEagerReading() )
85          {
86              executeEager( testsToRun, filter, computerWrapper.getComputer(), junitCore );
87          }
88          else
89          {
90              exeuteLazy( testsToRun, filter, computerWrapper.getComputer(), junitCore );
91          }
92  
93          String timeoutMessage = computerWrapper.describeElapsedTimeout();
94          if ( timeoutMessage.length() != 0 )
95          {
96              throw new TestSetFailedException( timeoutMessage );
97          }
98      }
99  
100     private static JUnitCore createJUnitCore( List<RunListener> listeners )
101     {
102         JUnitCore junitCore = new JUnitCore();
103         for ( RunListener runListener : listeners )
104         {
105             junitCore.addListener( runListener );
106         }
107         return junitCore;
108     }
109 
110     private static void executeEager(TestsToRun testsToRun, Filter filter, Computer computer, JUnitCore junitCore)
111             throws TestSetFailedException 
112     {
113         Class[] tests = testsToRun.getLocatedClasses();
114         createRequestAndRun( filter, computer, junitCore, tests );
115     }
116 
117     private static void exeuteLazy(TestsToRun testsToRun, Filter filter, Computer computer, JUnitCore junitCore)
118             throws TestSetFailedException
119     {
120         // in order to support LazyTestsToRun, the iterator must be used
121         for ( Class clazz : testsToRun )
122         {
123             createRequestAndRun( filter, computer, junitCore, clazz );
124         }
125     }
126 
127     private static void createRequestAndRun( Filter filter, Computer computer, JUnitCore junitCore, Class<?>... classesToRun )
128             throws TestSetFailedException
129     {
130         Request req = Request.classes( computer, classesToRun );
131         if ( filter != null )
132         {
133             req = new FilteringRequest( req, filter );
134             if ( req.getRunner() == null )
135             {
136                 // nothing to run
137                 return;
138             }
139         }
140 
141         final Result run = junitCore.run( req );
142         JUnit4RunListener.rethrowAnyTestMechanismFailures( run );
143     }
144 
145     private static ComputerWrapper createComputer( JUnitCoreParameters parameters )
146         throws TestSetFailedException
147     {
148         return parameters.isNoThreading() ? new ComputerWrapper( Computer.serial() ) : createParallelComputer( parameters );
149     }
150 
151     private static ComputerWrapper createParallelComputer( JUnitCoreParameters parameters )
152             throws TestSetFailedException
153     {
154         ParallelComputer pc = ParallelComputerFactory.createParallelComputer( parameters );
155 
156         int timeout = parameters.getParallelTestsTimeoutInSeconds();
157 
158         int timeoutForced = parameters.getParallelTestsTimeoutForcedInSeconds();
159 
160         Future<Collection<Description>> testsBeforeShutdown =
161                 timeout > 0 ? pc.scheduleShutdown( timeout, TimeUnit.SECONDS ) : null;
162 
163         Future<Collection<Description>> testsBeforeForcedShutdown =
164                 timeoutForced > 0 ? pc.scheduleForcedShutdown( timeoutForced, TimeUnit.SECONDS ) : null;
165 
166         return new ComputerWrapper( pc, timeout, testsBeforeShutdown, timeoutForced, testsBeforeForcedShutdown );
167     }
168 
169     private static class ComputerWrapper
170     {
171         private final Computer computer;
172         private final int timeout;
173         private final int timeoutForced;
174         private final Future<Collection<Description>> testsBeforeShutdown;
175         private final Future<Collection<Description>> testsBeforeForcedShutdown;
176 
177         ComputerWrapper( Computer computer )
178         {
179             this( computer, 0, null, 0, null );
180         }
181 
182         ComputerWrapper( Computer computer,
183                          int timeout, Future<Collection<Description>> testsBeforeShutdown,
184                          int timeoutForced, Future<Collection<Description>> testsBeforeForcedShutdown )
185         {
186             this.computer = computer;
187             this.timeout = timeout;
188             this.testsBeforeShutdown = testsBeforeShutdown;
189             this.timeoutForced = timeoutForced;
190             this.testsBeforeForcedShutdown = testsBeforeForcedShutdown;
191         }
192 
193         Computer getComputer()
194         {
195             return computer;
196         }
197 
198         String describeElapsedTimeout() throws TestSetFailedException
199         {
200             TreeSet<String> executedTests = new TreeSet<String>();
201             if ( timeout > 0 )
202             {
203                 executedTests.addAll( printShutdownHook( testsBeforeShutdown ) );
204             }
205 
206             if ( timeoutForced > 0 )
207             {
208                 executedTests.addAll( printShutdownHook( testsBeforeForcedShutdown ) );
209             }
210 
211             StringBuilder msg = new StringBuilder();
212             if ( !executedTests.isEmpty() )
213             {
214                 msg.append( "The test run has finished abruptly after timeout of " );
215                 msg.append( Math.min( timeout, timeoutForced ) );
216                 msg.append( " seconds.\n" );
217                 msg.append( "These tests were executed in prior of the shutdown operation:\n" );
218                 for ( String executedTest : executedTests )
219                 {
220                     msg.append( executedTest ).append( "\n" );
221                 }
222             }
223             return msg.toString();
224         }
225 
226         static Collection<String> printShutdownHook( Future<Collection<Description>> future )
227                 throws TestSetFailedException
228         {
229             if ( !future.isCancelled() && future.isDone() )
230             {
231                 try
232                 {
233                     TreeSet<String> executedTests = new TreeSet<String>();
234                     for ( Description executedTest : future.get() )
235                     {
236                         if ( executedTest != null && executedTest.getDisplayName() != null )
237                         {
238                             executedTests.add( executedTest.getDisplayName() );
239                         }
240                     }
241                     return executedTests;
242                 }
243                 catch ( Exception e )
244                 {
245                     throw new TestSetFailedException( e );
246                 }
247             }
248             return Collections.emptySet();
249         }
250     }
251 }