1 package org.apache.maven.surefire.testng;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.lang.annotation.Annotation;
24 import java.lang.reflect.Method;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.SortedMap;
31 import java.util.TreeMap;
32
33 import org.apache.maven.surefire.NonAbstractClassFilter;
34 import org.apache.maven.surefire.cli.CommandLineOption;
35 import org.apache.maven.surefire.report.ConsoleOutputCapture;
36 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
37 import org.apache.maven.surefire.report.ReportEntry;
38 import org.apache.maven.surefire.report.ReporterException;
39 import org.apache.maven.surefire.report.ReporterFactory;
40 import org.apache.maven.surefire.report.RunListener;
41 import org.apache.maven.surefire.report.SimpleReportEntry;
42 import org.apache.maven.surefire.testset.TestListResolver;
43 import org.apache.maven.surefire.testset.TestSetFailedException;
44 import org.apache.maven.surefire.util.RunOrderCalculator;
45 import org.apache.maven.surefire.util.ScanResult;
46 import org.apache.maven.surefire.util.TestsToRun;
47
48
49
50
51
52
53
54 public class TestNGDirectoryTestSuite
55 implements TestNgTestSuite
56 {
57
58 private final Map<String, String> options;
59
60 private final Map<String, String> junitOptions;
61
62 private final String testSourceDirectory;
63
64 private final File reportsDirectory;
65
66 private SortedMap<String, TestNGTestSet> testSets;
67
68 private final ScanResult scanResult;
69
70 private final TestListResolver methodFilter;
71
72 private final RunOrderCalculator runOrderCalculator;
73
74 private final Class<?> junitTestClass;
75
76 private final Class<? extends Annotation> junitRunWithAnnotation;
77
78 private final Class<? extends Annotation> junitTestAnnotation;
79
80 private final List<CommandLineOption> mainCliOptions;
81
82 private final int skipAfterFailureCount;
83
84 public TestNGDirectoryTestSuite( String testSourceDirectory, Map<String, String> confOptions, File reportsDirectory,
85 TestListResolver methodFilter, RunOrderCalculator runOrderCalculator,
86 ScanResult scanResult, List<CommandLineOption> mainCliOptions,
87 int skipAfterFailureCount )
88 {
89 this.runOrderCalculator = runOrderCalculator;
90 this.options = confOptions;
91 this.testSourceDirectory = testSourceDirectory;
92 this.reportsDirectory = reportsDirectory;
93 this.scanResult = scanResult;
94 this.methodFilter = methodFilter;
95 this.junitTestClass = findJUnitTestClass();
96 this.junitRunWithAnnotation = findJUnitRunWithAnnotation();
97 this.junitTestAnnotation = findJUnitTestAnnotation();
98 this.junitOptions = createJUnitOptions();
99 this.mainCliOptions = mainCliOptions;
100 this.skipAfterFailureCount = skipAfterFailureCount;
101 }
102
103 public void execute( TestsToRun testsToRun, ReporterFactory reporterManagerFactory )
104 throws TestSetFailedException
105 {
106
107 if ( !testsToRun.allowEagerReading() )
108 {
109 executeLazy( testsToRun, reporterManagerFactory );
110 }
111 else if ( testsToRun.containsAtLeast( 2 ) )
112 {
113 executeMulti( testsToRun, reporterManagerFactory );
114 }
115 else if ( testsToRun.containsAtLeast( 1 ) )
116 {
117 Class<?> testClass = testsToRun.iterator().next();
118 executeSingleClass( reporterManagerFactory, testClass );
119 }
120 }
121
122 private void executeSingleClass( ReporterFactory reporterManagerFactory, Class<?> testClass )
123 throws TestSetFailedException
124 {
125 options.put( "suitename", testClass.getName() );
126
127 RunListener reporter = reporterManagerFactory.createReporter();
128 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
129
130 startTestSuite( reporter, this );
131
132 final Map<String, String> optionsToUse = isJUnitTest( testClass ) ? junitOptions : options;
133
134 TestNGExecutor.run( new Class<?>[]{ testClass }, testSourceDirectory, optionsToUse, reporter, this,
135 reportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
136
137 finishTestSuite( reporter, this );
138 }
139
140 public void executeLazy( TestsToRun testsToRun, ReporterFactory reporterFactory )
141 throws TestSetFailedException
142 {
143 for ( Class<?> c : testsToRun )
144 {
145 executeSingleClass( reporterFactory, c );
146 }
147 }
148
149 private Class<?> findJUnitTestClass()
150 {
151 return lookupClass( "junit.framework.Test" );
152 }
153
154 private Class<Annotation> findJUnitRunWithAnnotation()
155 {
156 return lookupAnnotation( "org.junit.runner.RunWith" );
157 }
158
159 private Class<Annotation> findJUnitTestAnnotation()
160 {
161 return lookupAnnotation( "org.junit.Test" );
162 }
163
164 @SuppressWarnings( "unchecked" )
165 private static Class<Annotation> lookupAnnotation( String className )
166 {
167 Class<Annotation> junitClass;
168 try
169 {
170 junitClass = (Class<Annotation>) Class.forName( className );
171 }
172 catch ( ClassNotFoundException e )
173 {
174 junitClass = null;
175 }
176 return junitClass;
177 }
178
179 private static Class<?> lookupClass( String className )
180 {
181 Class<?> junitClass;
182 try
183 {
184 junitClass = Class.forName( className );
185 }
186 catch ( ClassNotFoundException e )
187 {
188 junitClass = null;
189 }
190 return junitClass;
191 }
192
193 public void executeMulti( TestsToRun testsToRun, ReporterFactory reporterFactory )
194 throws TestSetFailedException
195 {
196 List<Class<?>> testNgTestClasses = new ArrayList<Class<?>>();
197 List<Class<?>> junitTestClasses = new ArrayList<Class<?>>();
198 for ( Class<?> c : testsToRun )
199 {
200 if ( isJUnitTest( c ) )
201 {
202 junitTestClasses.add( c );
203 }
204 else
205 {
206 testNgTestClasses.add( c );
207 }
208 }
209
210 File testNgReportsDirectory = reportsDirectory, junitReportsDirectory = reportsDirectory;
211
212 if ( !junitTestClasses.isEmpty() && !testNgTestClasses.isEmpty() )
213 {
214 testNgReportsDirectory = new File( reportsDirectory, "testng-native-results" );
215 junitReportsDirectory = new File( reportsDirectory, "testng-junit-results" );
216 }
217
218 RunListener reporterManager = reporterFactory.createReporter();
219 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporterManager );
220 startTestSuite( reporterManager, this );
221
222 Class<?>[] testClasses = testNgTestClasses.toArray( new Class<?>[testNgTestClasses.size()] );
223
224 TestNGExecutor.run( testClasses, testSourceDirectory, options, reporterManager, this,
225 testNgReportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
226
227 if ( !junitTestClasses.isEmpty() )
228 {
229 testClasses = junitTestClasses.toArray( new Class[junitTestClasses.size()] );
230
231 TestNGExecutor.run( testClasses, testSourceDirectory, junitOptions, reporterManager, this,
232 junitReportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
233 }
234
235 finishTestSuite( reporterManager, this );
236 }
237
238 private boolean isJUnitTest( Class<?> c )
239 {
240 return isJunit3Test( c ) || isJunit4Test( c );
241 }
242
243 private boolean isJunit4Test( Class<?> c )
244 {
245 return hasJunit4RunWithAnnotation( c ) || hasJunit4TestAnnotation( c );
246 }
247
248 private boolean hasJunit4RunWithAnnotation( Class<?> c )
249 {
250 return junitRunWithAnnotation != null && c.getAnnotation( junitRunWithAnnotation ) != null;
251 }
252
253 private boolean hasJunit4TestAnnotation( Class<?> c )
254 {
255 if ( junitTestAnnotation != null )
256 {
257 for ( Method m : c.getMethods() )
258 {
259 if ( m.getAnnotation( junitTestAnnotation ) != null )
260 {
261 return true;
262 }
263 }
264 }
265
266 return false;
267 }
268
269 private boolean isJunit3Test( Class<?> c )
270 {
271 return junitTestClass != null && junitTestClass.isAssignableFrom( c );
272 }
273
274 private Map<String, String> createJUnitOptions()
275 {
276 Map<String, String> junitOptions = new HashMap<String, String>( this.options );
277 junitOptions.put( "junit", "true" );
278 return junitOptions;
279 }
280
281
282 public void execute( String testSetName, ReporterFactory reporterManagerFactory )
283 throws TestSetFailedException
284 {
285 if ( testSets == null )
286 {
287 throw new IllegalStateException( "You must call locateTestSets before calling execute" );
288 }
289 TestNGTestSet testSet = testSets.get( testSetName );
290
291 if ( testSet == null )
292 {
293 throw new TestSetFailedException( "Unable to find test set '" + testSetName + "' in suite" );
294 }
295
296 RunListener reporter = reporterManagerFactory.createReporter();
297 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
298
299 startTestSuite( reporter, this );
300
301 TestNGExecutor.run( new Class<?>[] { testSet.getTestClass() }, testSourceDirectory, options, reporter,
302 this, reportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
303
304 finishTestSuite( reporter, this );
305 }
306
307 public static void startTestSuite( RunListener reporter, Object suite )
308 {
309 ReportEntry report = new SimpleReportEntry( suite.getClass().getName(), getSuiteName( suite ) );
310
311 try
312 {
313 reporter.testSetStarting( report );
314 }
315 catch ( ReporterException e )
316 {
317
318 }
319 }
320
321 public static void finishTestSuite( RunListener reporterManager, Object suite )
322 {
323 ReportEntry report = new SimpleReportEntry( suite.getClass().getName(), getSuiteName( suite ) );
324
325 reporterManager.testSetCompleted( report );
326 }
327
328 public String getSuiteName()
329 {
330 String result = options.get( "suitename" );
331 return result == null ? "TestSuite" : result;
332 }
333
334 private static String getSuiteName( Object suite )
335 {
336 String result = "TestSuite";
337 if ( suite instanceof TestNGDirectoryTestSuite )
338 {
339 result = ( (TestNGDirectoryTestSuite) suite ).getSuiteName();
340 }
341 else if ( suite instanceof TestNGXmlTestSuite )
342 {
343 result = ( (TestNGXmlTestSuite) suite ).getSuiteName();
344 }
345
346 return result;
347 }
348
349 public Map locateTestSets( ClassLoader classLoader )
350 throws TestSetFailedException
351 {
352 if ( testSets != null )
353 {
354 throw new IllegalStateException( "You can't call locateTestSets twice" );
355 }
356 testSets = new TreeMap<String, TestNGTestSet>();
357
358 final TestsToRun scanned = scanResult.applyFilter( new NonAbstractClassFilter(), classLoader );
359
360 final TestsToRun testsToRun = runOrderCalculator.orderTestClasses( scanned );
361
362 for ( Class<?> testClass : testsToRun )
363 {
364 TestNGTestSet testSet = new TestNGTestSet( testClass );
365
366 if ( testSets.containsKey( testSet.getName() ) )
367 {
368 throw new TestSetFailedException( "Duplicate test set '" + testSet.getName() + "'" );
369 }
370 testSets.put( testSet.getName(), testSet );
371 }
372
373 return Collections.unmodifiableSortedMap( testSets );
374 }
375
376 }