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