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