1 package org.apache.maven.surefire.junit4;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Set;
28
29 import org.apache.maven.shared.utils.io.SelectorUtils;
30 import org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil;
31 import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
32 import org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory;
33 import org.apache.maven.surefire.common.junit4.JUnit4TestChecker;
34 import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
35 import org.apache.maven.surefire.providerapi.AbstractProvider;
36 import org.apache.maven.surefire.providerapi.ProviderParameters;
37 import org.apache.maven.surefire.report.ConsoleOutputCapture;
38 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
39 import org.apache.maven.surefire.report.PojoStackTraceWriter;
40 import org.apache.maven.surefire.report.ReportEntry;
41 import org.apache.maven.surefire.report.ReporterFactory;
42 import org.apache.maven.surefire.report.RunListener;
43 import org.apache.maven.surefire.report.SimpleReportEntry;
44 import org.apache.maven.surefire.suite.RunResult;
45 import org.apache.maven.surefire.testset.TestSetFailedException;
46 import org.apache.maven.surefire.util.RunOrderCalculator;
47 import org.apache.maven.surefire.util.ScanResult;
48 import org.apache.maven.surefire.util.TestsToRun;
49 import org.apache.maven.surefire.util.internal.StringUtils;
50 import org.junit.runner.Description;
51 import org.junit.runner.Request;
52 import org.junit.runner.Result;
53 import org.junit.runner.notification.RunNotifier;
54
55
56
57
58 public class JUnit4Provider
59 extends AbstractProvider
60 {
61 private final ClassLoader testClassLoader;
62
63 private final List<org.junit.runner.notification.RunListener> customRunListeners;
64
65 private final JUnit4TestChecker jUnit4TestChecker;
66
67 private final String requestedTestMethod;
68
69 private final ProviderParameters providerParameters;
70
71 private final RunOrderCalculator runOrderCalculator;
72
73 private final ScanResult scanResult;
74
75 private final int rerunFailingTestsCount;
76
77 private TestsToRun testsToRun;
78
79 public JUnit4Provider( ProviderParameters booterParameters )
80 {
81 providerParameters = booterParameters;
82 testClassLoader = booterParameters.getTestClassLoader();
83 scanResult = booterParameters.getScanResult();
84 runOrderCalculator = booterParameters.getRunOrderCalculator();
85 customRunListeners = JUnit4RunListenerFactory.
86 createCustomListeners( booterParameters.getProviderProperties().getProperty( "listener" ) );
87 jUnit4TestChecker = new JUnit4TestChecker( testClassLoader );
88 requestedTestMethod = booterParameters.getTestRequest().getRequestedTestMethod();
89 rerunFailingTestsCount = booterParameters.getTestRequest().getRerunFailingTestsCount();
90 }
91
92 public RunResult invoke( Object forkTestSet )
93 throws TestSetFailedException
94 {
95 if ( testsToRun == null )
96 {
97 if ( forkTestSet instanceof TestsToRun )
98 {
99 testsToRun = (TestsToRun) forkTestSet;
100 }
101 else if ( forkTestSet instanceof Class )
102 {
103 testsToRun = TestsToRun.fromClass( (Class) forkTestSet );
104 }
105 else
106 {
107 testsToRun = scanClassPath();
108 }
109 }
110
111 upgradeCheck();
112
113 final ReporterFactory reporterFactory = providerParameters.getReporterFactory();
114
115 RunListener reporter = reporterFactory.createReporter();
116
117 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
118
119 JUnit4RunListener jUnit4TestSetReporter = new JUnit4RunListener( reporter );
120
121 Result result = new Result();
122 RunNotifier runNotifier = getRunNotifier( jUnit4TestSetReporter, result, customRunListeners );
123
124 runNotifier.fireTestRunStarted( createTestsDescription() );
125
126 for ( Class aTestsToRun : testsToRun )
127 {
128 executeTestSet( aTestsToRun, reporter, runNotifier );
129 }
130
131 runNotifier.fireTestRunFinished( result );
132
133 JUnit4RunListener.rethrowAnyTestMechanismFailures( result );
134
135 closeRunNotifier( jUnit4TestSetReporter, customRunListeners );
136 return reporterFactory.close();
137 }
138
139 private void executeTestSet( Class<?> clazz, RunListener reporter, RunNotifier listeners )
140 {
141 final ReportEntry report = new SimpleReportEntry( getClass().getName(), clazz.getName() );
142 reporter.testSetStarting( report );
143 try
144 {
145 if ( !StringUtils.isBlank( requestedTestMethod ) )
146 {
147 String actualTestMethod = getMethod( clazz, requestedTestMethod );
148 String[] testMethods = StringUtils.split( actualTestMethod, "+" );
149 executeWithRerun( clazz, listeners, testMethods );
150 }
151 else
152 {
153 executeWithRerun( clazz, listeners, null );
154 }
155 }
156 catch ( Throwable e )
157 {
158 reporter.testError( SimpleReportEntry.withException( report.getSourceName(), report.getName(),
159 new PojoStackTraceWriter( report.getSourceName(),
160 report.getName(), e ) ) );
161 }
162 finally
163 {
164 reporter.testSetCompleted( report );
165 }
166 }
167
168 private void executeWithRerun( Class<?> clazz, RunNotifier listeners, String[] testMethods )
169 {
170 JUnitTestFailureListener failureListener = new JUnitTestFailureListener();
171 listeners.addListener( failureListener );
172
173 execute( clazz, listeners, testMethods );
174
175
176 if ( rerunFailingTestsCount > 0 )
177 {
178 for ( int i = 0; i < rerunFailingTestsCount && !failureListener.getAllFailures().isEmpty(); i++ )
179 {
180 Set<String> methodsSet = JUnit4ProviderUtil.generateFailingTests( failureListener.getAllFailures() );
181 String[] methods = methodsSet.toArray( new String[ methodsSet.size() ] );
182 failureListener.reset();
183 execute( clazz, listeners, methods );
184 }
185 }
186 }
187
188 private RunNotifier getRunNotifier( org.junit.runner.notification.RunListener main, Result result,
189 List<org.junit.runner.notification.RunListener> others )
190 {
191 RunNotifier fNotifier = new RunNotifier();
192 fNotifier.addListener( main );
193 fNotifier.addListener( result.createListener() );
194 for ( org.junit.runner.notification.RunListener listener : others )
195 {
196 fNotifier.addListener( listener );
197 }
198 return fNotifier;
199 }
200
201
202
203 private void closeRunNotifier( org.junit.runner.notification.RunListener main,
204 List<org.junit.runner.notification.RunListener> others )
205 {
206 RunNotifier fNotifier = new RunNotifier();
207 fNotifier.removeListener( main );
208 for ( org.junit.runner.notification.RunListener listener : others )
209 {
210 fNotifier.removeListener( listener );
211 }
212 }
213
214 public Iterator<?> getSuites()
215 {
216 testsToRun = scanClassPath();
217 return testsToRun.iterator();
218 }
219
220 private TestsToRun scanClassPath()
221 {
222 final TestsToRun scannedClasses = scanResult.applyFilter( jUnit4TestChecker, testClassLoader );
223 return runOrderCalculator.orderTestClasses( scannedClasses );
224 }
225
226 @SuppressWarnings( "unchecked" )
227 private void upgradeCheck()
228 throws TestSetFailedException
229 {
230 if ( isJUnit4UpgradeCheck() )
231 {
232 List<Class> classesSkippedByValidation =
233 scanResult.getClassesSkippedByValidation( jUnit4TestChecker, testClassLoader );
234 if ( !classesSkippedByValidation.isEmpty() )
235 {
236 StringBuilder reason = new StringBuilder();
237 reason.append( "Updated check failed\n" );
238 reason.append( "There are tests that would be run with junit4 / surefire 2.6 but not with [2.7,):\n" );
239 for ( Class testClass : classesSkippedByValidation )
240 {
241 reason.append( " " );
242 reason.append( testClass.getName() );
243 reason.append( "\n" );
244 }
245 throw new TestSetFailedException( reason.toString() );
246 }
247 }
248 }
249
250 private Description createTestsDescription()
251 {
252 Collection<Class<?>> classes = new ArrayList<Class<?>>();
253 for ( Class<?> clazz : testsToRun )
254 {
255 classes.add( clazz );
256 }
257 return JUnit4ProviderUtil.createSuiteDescription( classes );
258 }
259
260 private static boolean isJUnit4UpgradeCheck()
261 {
262 return System.getProperty( "surefire.junit4.upgradecheck" ) != null;
263 }
264
265 private static void execute( Class<?> testClass, RunNotifier fNotifier, String[] testMethods )
266 {
267 if ( testMethods != null )
268 {
269 for ( final Method method : testClass.getMethods() )
270 {
271 for ( final String testMethod : testMethods )
272 {
273 if ( SelectorUtils.match( testMethod, method.getName() ) )
274 {
275 Request.method( testClass, method.getName() ).getRunner().run( fNotifier );
276 }
277
278 }
279 }
280 }
281 else
282 {
283 Request.aClass( testClass ).getRunner().run( fNotifier );
284 }
285 }
286
287
288
289
290
291
292
293
294
295
296 private static String getMethod( Class testClass, String testMethodStr )
297 {
298 final String className = testClass.getName();
299
300 if ( !testMethodStr.contains( "#" ) && !testMethodStr.contains( "," ) )
301 {
302 return testMethodStr;
303 }
304 testMethodStr += ",";
305 final int beginIndex = testMethodStr.indexOf( className );
306 final int endIndex = testMethodStr.indexOf( ",", beginIndex );
307 final String classMethodStr =
308 testMethodStr.substring( beginIndex, endIndex );
309
310 final int index = classMethodStr.indexOf( '#' );
311 return index >= 0 ? classMethodStr.substring( index + 1, classMethodStr.length() ) : null;
312 }
313 }