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 org.apache.maven.surefire.booter.Command;
23  import org.apache.maven.surefire.booter.CommandListener;
24  import org.apache.maven.surefire.booter.CommandReader;
25  import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
26  import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
27  import org.apache.maven.surefire.common.junit4.Notifier;
28  import org.apache.maven.surefire.common.junit48.FilterFactory;
29  import org.apache.maven.surefire.common.junit48.JUnit48Reflector;
30  import org.apache.maven.surefire.common.junit48.JUnit48TestChecker;
31  import org.apache.maven.surefire.providerapi.AbstractProvider;
32  import org.apache.maven.surefire.providerapi.ProviderParameters;
33  import org.apache.maven.surefire.report.ConsoleStream;
34  import org.apache.maven.surefire.report.ReporterFactory;
35  import org.apache.maven.surefire.suite.RunResult;
36  import org.apache.maven.surefire.testset.TestListResolver;
37  import org.apache.maven.surefire.testset.TestSetFailedException;
38  import org.apache.maven.surefire.util.RunOrderCalculator;
39  import org.apache.maven.surefire.util.ScanResult;
40  import org.apache.maven.surefire.util.ScannerFilter;
41  import org.apache.maven.surefire.util.TestsToRun;
42  import org.junit.runner.manipulation.Filter;
43  import org.junit.runner.notification.Failure;
44  
45  import java.util.List;
46  import java.util.Map;
47  import java.util.Set;
48  import java.util.concurrent.ConcurrentHashMap;
49  
50  import static org.apache.maven.surefire.booter.CommandReader.getReader;
51  import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests;
52  import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
53  import static org.apache.maven.surefire.common.junit4.Notifier.pureNotifier;
54  import static org.apache.maven.surefire.junitcore.ConcurrentRunListener.createInstance;
55  import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture;
56  import static org.apache.maven.surefire.testset.TestListResolver.optionallyWildcardFilter;
57  import static org.apache.maven.surefire.util.TestsToRun.fromClass;
58  
59  /**
60   * @author Kristian Rosenvold
61   */
62  @SuppressWarnings( { "UnusedDeclaration" } )
63  public class JUnitCoreProvider
64      extends AbstractProvider
65  {
66      private final ClassLoader testClassLoader;
67  
68      private final JUnitCoreParameters jUnitCoreParameters;
69  
70      private final ScannerFilter scannerFilter;
71  
72      private final String customRunListeners;
73  
74      private final ProviderParameters providerParameters;
75  
76      private final ScanResult scanResult;
77  
78      private final int rerunFailingTestsCount;
79  
80      private final JUnit48Reflector jUnit48Reflector;
81  
82      private final RunOrderCalculator runOrderCalculator;
83  
84      private final TestListResolver testResolver;
85  
86      private final CommandReader commandsReader;
87  
88      private TestsToRun testsToRun;
89  
90      public JUnitCoreProvider( ProviderParameters bootParams )
91      {
92          // don't start a thread in CommandReader while we are in in-plugin process
93          commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
94          providerParameters = bootParams;
95          testClassLoader = bootParams.getTestClassLoader();
96          scanResult = bootParams.getScanResult();
97          runOrderCalculator = bootParams.getRunOrderCalculator();
98          jUnitCoreParameters = new JUnitCoreParameters( bootParams.getProviderProperties() );
99          scannerFilter = new JUnit48TestChecker( testClassLoader );
100         testResolver = bootParams.getTestRequest().getTestListResolver();
101         rerunFailingTestsCount = bootParams.getTestRequest().getRerunFailingTestsCount();
102         customRunListeners = bootParams.getProviderProperties().get( "listener" );
103         jUnit48Reflector = new JUnit48Reflector( testClassLoader );
104     }
105 
106     @Override
107     public Iterable<Class<?>> getSuites()
108     {
109         testsToRun = scanClassPath();
110         return testsToRun;
111     }
112 
113     private boolean isSingleThreaded()
114     {
115         return jUnitCoreParameters.isNoThreading();
116     }
117 
118     @Override
119     public RunResult invoke( Object forkTestSet )
120         throws TestSetFailedException
121     {
122         final ReporterFactory reporterFactory = providerParameters.getReporterFactory();
123 
124         final ConsoleStream consoleStream = providerParameters.getConsoleLogger();
125 
126         Filter filter = jUnit48Reflector.isJUnit48Available() ? createJUnit48Filter() : null;
127 
128         Notifier notifier =
129             new Notifier( createRunListener( reporterFactory, consoleStream ), getSkipAfterFailureCount() );
130         // startCapture() called in createRunListener() in prior to setTestsToRun()
131 
132         if ( testsToRun == null )
133         {
134             setTestsToRun( forkTestSet );
135         }
136 
137         // Add test failure listener
138         JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener();
139         notifier.addListener( testFailureListener );
140 
141         if ( isFailFast() && commandsReader != null )
142         {
143             registerPleaseStopJUnitListener( notifier );
144         }
145 
146         final RunResult runResult;
147 
148         try
149         {
150             JUnitCoreWrapper core = new JUnitCoreWrapper( notifier, jUnitCoreParameters, consoleStream );
151 
152             if ( commandsReader != null )
153             {
154                 registerShutdownListener( testsToRun );
155                 commandsReader.awaitStarted();
156             }
157 
158             notifier.asFailFast( isFailFast() );
159             core.execute( testsToRun, createCustomListeners( customRunListeners ), filter );
160             notifier.asFailFast( false );
161 
162             // Rerun failing tests if rerunFailingTestsCount is larger than 0
163             if ( isRerunFailingTests() )
164             {
165                 Notifier rerunNotifier = pureNotifier();
166                 notifier.copyListenersTo( rerunNotifier );
167                 JUnitCoreWrapper rerunCore = new JUnitCoreWrapper( rerunNotifier, jUnitCoreParameters, consoleStream );
168                 for ( int i = 0; i < rerunFailingTestsCount && !testFailureListener.getAllFailures().isEmpty(); i++ )
169                 {
170                     List<Failure> failures = testFailureListener.getAllFailures();
171                     Map<Class<?>, Set<String>> failingTests = generateFailingTests( failures, testClassLoader );
172                     testFailureListener.reset();
173                     FilterFactory filterFactory = new FilterFactory( testClassLoader );
174                     Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests );
175                     rerunCore.execute( testsToRun, failingMethodsFilter );
176                 }
177             }
178         }
179         finally
180         {
181             runResult = reporterFactory.close();
182             notifier.removeListeners();
183         }
184         return runResult;
185     }
186 
187     private void setTestsToRun( Object forkTestSet )
188         throws TestSetFailedException
189     {
190         if ( forkTestSet instanceof TestsToRun )
191         {
192             testsToRun = (TestsToRun) forkTestSet;
193         }
194         else if ( forkTestSet instanceof Class )
195         {
196             Class<?> theClass = (Class<?>) forkTestSet;
197             testsToRun = fromClass( theClass );
198         }
199         else
200         {
201             testsToRun = scanClassPath();
202         }
203     }
204 
205     private boolean isRerunFailingTests()
206     {
207         return rerunFailingTestsCount > 0;
208     }
209 
210     private boolean isFailFast()
211     {
212         return providerParameters.getSkipAfterFailureCount() > 0;
213     }
214 
215     private int getSkipAfterFailureCount()
216     {
217         return isFailFast() ? providerParameters.getSkipAfterFailureCount() : 0;
218     }
219 
220     private void registerShutdownListener( final TestsToRun testsToRun )
221     {
222         commandsReader.addShutdownListener( new CommandListener()
223         {
224             @Override
225             public void update( Command command )
226             {
227                 testsToRun.markTestSetFinished();
228             }
229         } );
230     }
231 
232     private void registerPleaseStopJUnitListener( final Notifier stoppable )
233     {
234         commandsReader.addSkipNextTestsListener( new CommandListener()
235         {
236             @Override
237             public void update( Command command )
238             {
239                 stoppable.pleaseStop();
240             }
241         } );
242     }
243 
244     private JUnit4RunListener createRunListener( ReporterFactory reporterFactory, ConsoleStream consoleStream )
245         throws TestSetFailedException
246     {
247         if ( isSingleThreaded() )
248         {
249             NonConcurrentRunListener rm = new NonConcurrentRunListener( reporterFactory.createReporter() );
250             startCapture( rm );
251             return rm;
252         }
253         else
254         {
255             final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>();
256 
257             ConcurrentRunListener listener = createInstance( testSetMap, reporterFactory, isParallelTypes(),
258                                                              isParallelMethodsAndTypes(), consoleStream );
259             startCapture( listener );
260 
261             return new JUnitCoreRunListener( listener, testSetMap );
262         }
263     }
264 
265     private boolean isParallelMethodsAndTypes()
266     {
267         return jUnitCoreParameters.isParallelMethods() && isParallelTypes();
268     }
269 
270     private boolean isParallelTypes()
271     {
272         return jUnitCoreParameters.isParallelClasses() || jUnitCoreParameters.isParallelSuites();
273     }
274 
275     private Filter createJUnit48Filter()
276     {
277         final FilterFactory factory = new FilterFactory( testClassLoader );
278         Map<String, String> props = providerParameters.getProviderProperties();
279         Filter groupFilter = factory.canCreateGroupFilter( props ) ? factory.createGroupFilter( props ) : null;
280         TestListResolver methodFilter = optionallyWildcardFilter( testResolver );
281         boolean onlyGroups = methodFilter.isEmpty() || methodFilter.isWildcard();
282         if ( onlyGroups )
283         {
284             return groupFilter;
285         }
286         else
287         {
288             Filter jUnitMethodFilter = factory.createMethodFilter( methodFilter );
289             return groupFilter == null ? jUnitMethodFilter : factory.and( groupFilter, jUnitMethodFilter );
290         }
291     }
292 
293     private TestsToRun scanClassPath()
294     {
295         TestsToRun scanned = scanResult.applyFilter( scannerFilter, testClassLoader );
296         return runOrderCalculator.orderTestClasses( scanned );
297     }
298 }