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 org.apache.maven.surefire.booter.ProviderParameterNames;
23 import org.apache.maven.surefire.report.RunListener;
24 import org.apache.maven.surefire.testng.conf.Configurator;
25 import org.apache.maven.surefire.testset.TestSetFailedException;
26 import org.apache.maven.surefire.util.ReflectionUtils;
27 import org.apache.maven.surefire.util.internal.StringUtils;
28 import org.testng.TestNG;
29 import org.testng.annotations.Test;
30 import org.testng.xml.XmlClass;
31 import org.testng.xml.XmlMethodSelector;
32 import org.testng.xml.XmlSuite;
33 import org.testng.xml.XmlTest;
34
35 import java.io.File;
36 import java.lang.annotation.Annotation;
37 import java.lang.reflect.Constructor;
38 import java.lang.reflect.InvocationTargetException;
39 import java.lang.reflect.Method;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44
45
46
47
48
49
50
51 public class TestNGExecutor
52 {
53
54 public static final String DEFAULT_SUREFIRE_SUITE_NAME = "Surefire suite";
55
56
57 public static final String DEFAULT_SUREFIRE_TEST_NAME = "Surefire test";
58
59 private static final boolean HAS_TEST_ANNOTATION_ON_CLASSPATH =
60 null != ReflectionUtils.tryLoadClass( TestNGExecutor.class.getClassLoader(), "org.testng.annotations.Test" );
61
62 private TestNGExecutor()
63 {
64
65 }
66
67 public static void run( Class[] testClasses, String testSourceDirectory, Map options, RunListener reportManager,
68 TestNgTestSuite suite, File reportsDirectory, final String methodNamePattern )
69 throws TestSetFailedException
70 {
71 TestNG testng = new TestNG( true );
72
73 Configurator configurator = getConfigurator( (String) options.get( "testng.configurator" ) );
74 System.out.println( "Configuring TestNG with: " + configurator.getClass().getSimpleName() );
75
76 XmlMethodSelector groupMatchingSelector = getGroupMatchingSelector( options );
77 XmlMethodSelector methodNameFilteringSelector = getMethodNameFilteringSelector( methodNamePattern );
78
79 Map<String, SuiteAndNamedTests> suitesNames = new HashMap<String, SuiteAndNamedTests>();
80
81 List<XmlSuite> xmlSuites = new ArrayList<XmlSuite>();
82 for ( Class testClass : testClasses )
83 {
84 TestMetadata metadata = findTestMetadata( testClass );
85
86 SuiteAndNamedTests suiteAndNamedTests = suitesNames.get( metadata.suiteName );
87 if ( suiteAndNamedTests == null )
88 {
89 suiteAndNamedTests = new SuiteAndNamedTests();
90 suiteAndNamedTests.xmlSuite.setName( metadata.suiteName );
91 configurator.configure( suiteAndNamedTests.xmlSuite, options );
92 xmlSuites.add( suiteAndNamedTests.xmlSuite );
93
94 suitesNames.put( metadata.suiteName, suiteAndNamedTests );
95 }
96
97 XmlTest xmlTest = suiteAndNamedTests.testNameToTest.get( metadata.testName );
98 if ( xmlTest == null )
99 {
100 xmlTest = new XmlTest( suiteAndNamedTests.xmlSuite );
101 xmlTest.setName( metadata.testName );
102 addSelector( xmlTest, groupMatchingSelector );
103 addSelector( xmlTest, methodNameFilteringSelector );
104 xmlTest.setXmlClasses( new ArrayList<XmlClass>() );
105
106 suiteAndNamedTests.testNameToTest.put( metadata.testName, xmlTest );
107 }
108
109 xmlTest.getXmlClasses().add( new XmlClass( testClass.getName() ) );
110 }
111
112 testng.setXmlSuites( xmlSuites );
113 configurator.configure( testng, options );
114 postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory );
115 testng.run();
116 }
117
118 private static TestMetadata findTestMetadata( Class testClass )
119 {
120 TestMetadata result = new TestMetadata();
121 if ( HAS_TEST_ANNOTATION_ON_CLASSPATH )
122 {
123 Test testAnnotation = findAnnotation( testClass, Test.class );
124 if ( null != testAnnotation )
125 {
126 if ( !StringUtils.isBlank( testAnnotation.suiteName() ) )
127 {
128 result.suiteName = testAnnotation.suiteName();
129 }
130
131 if ( !StringUtils.isBlank( testAnnotation.testName() ) )
132 {
133 result.testName = testAnnotation.testName();
134 }
135 }
136 }
137 return result;
138 }
139
140 private static <T extends Annotation> T findAnnotation( Class<?> clazz, Class<T> annotationType )
141 {
142 if ( clazz == null )
143 {
144 return null;
145 }
146
147 T result = clazz.getAnnotation( annotationType );
148 if ( result != null )
149 {
150 return result;
151 }
152
153 return findAnnotation( clazz.getSuperclass(), annotationType );
154 }
155
156 private static class TestMetadata
157 {
158 private String testName = DEFAULT_SUREFIRE_TEST_NAME;
159
160 private String suiteName = DEFAULT_SUREFIRE_SUITE_NAME;
161 }
162
163 private static class SuiteAndNamedTests
164 {
165 private XmlSuite xmlSuite = new XmlSuite();
166
167 private Map<String, XmlTest> testNameToTest = new HashMap<String, XmlTest>();
168 }
169
170 private static void addSelector( XmlTest xmlTest, XmlMethodSelector selector )
171 {
172 if ( selector != null )
173 {
174 xmlTest.getMethodSelectors().add( selector );
175 }
176 }
177
178 @SuppressWarnings( "checkstyle:magicnumber" )
179 private static XmlMethodSelector getMethodNameFilteringSelector( String methodNamePattern )
180 throws TestSetFailedException
181 {
182 if ( StringUtils.isBlank( methodNamePattern ) )
183 {
184 return null;
185 }
186
187
188 String clazzName = "org.apache.maven.surefire.testng.utils.MethodSelector";
189 try
190 {
191 Class clazz = Class.forName( clazzName );
192
193 Method method = clazz.getMethod( "setMethodName", new Class[] { String.class } );
194 method.invoke( null, methodNamePattern );
195 }
196 catch ( ClassNotFoundException e )
197 {
198 throw new TestSetFailedException( e.getMessage(), e );
199 }
200 catch ( SecurityException e )
201 {
202 throw new TestSetFailedException( e.getMessage(), e );
203 }
204 catch ( NoSuchMethodException e )
205 {
206 throw new TestSetFailedException( e.getMessage(), e );
207 }
208 catch ( IllegalArgumentException e )
209 {
210 throw new TestSetFailedException( e.getMessage(), e );
211 }
212 catch ( IllegalAccessException e )
213 {
214 throw new TestSetFailedException( e.getMessage(), e );
215 }
216 catch ( InvocationTargetException e )
217 {
218 throw new TestSetFailedException( e.getMessage(), e );
219 }
220
221 XmlMethodSelector xms = new XmlMethodSelector();
222
223 xms.setName( clazzName );
224
225 xms.setPriority( 10000 );
226
227 return xms;
228 }
229
230 @SuppressWarnings( "checkstyle:magicnumber" )
231 private static XmlMethodSelector getGroupMatchingSelector( Map options )
232 throws TestSetFailedException
233 {
234 String groups = (String) options.get( ProviderParameterNames.TESTNG_GROUPS_PROP );
235 String excludedGroups = (String) options.get( ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP );
236
237 if ( groups == null && excludedGroups == null )
238 {
239 return null;
240 }
241
242
243 String clazzName = "org.apache.maven.surefire.testng.utils.GroupMatcherMethodSelector";
244 try
245 {
246 Class clazz = Class.forName( clazzName );
247
248
249 Method method = clazz.getMethod( "setGroups", new Class[] { String.class, String.class } );
250 method.invoke( null, groups, excludedGroups );
251 }
252 catch ( ClassNotFoundException e )
253 {
254 throw new TestSetFailedException( e.getMessage(), e );
255 }
256 catch ( SecurityException e )
257 {
258 throw new TestSetFailedException( e.getMessage(), e );
259 }
260 catch ( NoSuchMethodException e )
261 {
262 throw new TestSetFailedException( e.getMessage(), e );
263 }
264 catch ( IllegalArgumentException e )
265 {
266 throw new TestSetFailedException( e.getMessage(), e );
267 }
268 catch ( IllegalAccessException e )
269 {
270 throw new TestSetFailedException( e.getMessage(), e );
271 }
272 catch ( InvocationTargetException e )
273 {
274 throw new TestSetFailedException( e.getMessage(), e );
275 }
276
277 XmlMethodSelector xms = new XmlMethodSelector();
278
279 xms.setName( clazzName );
280
281 xms.setPriority( 9999 );
282
283 return xms;
284 }
285
286 public static void run( List<String> suiteFiles, String testSourceDirectory, Map options,
287 RunListener reportManager, TestNgTestSuite suite, File reportsDirectory )
288 throws TestSetFailedException
289 {
290 TestNG testng = new TestNG( true );
291 Configurator configurator = getConfigurator( (String) options.get( "testng.configurator" ) );
292 configurator.configure( testng, options );
293 postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory );
294 testng.setTestSuites( suiteFiles );
295 testng.run();
296 }
297
298 private static Configurator getConfigurator( String className )
299 {
300 try
301 {
302 return (Configurator) Class.forName( className ).newInstance();
303 }
304 catch ( InstantiationException e )
305 {
306 throw new RuntimeException( e );
307 }
308 catch ( IllegalAccessException e )
309 {
310 throw new RuntimeException( e );
311 }
312 catch ( ClassNotFoundException e )
313 {
314 throw new RuntimeException( e );
315 }
316 }
317
318 private static void postConfigure( TestNG testNG, String sourcePath, RunListener reportManager,
319 TestNgTestSuite suite, File reportsDirectory )
320 throws TestSetFailedException
321 {
322
323 testNG.setVerbose( 0 );
324
325 TestNGReporter reporter = createTestNGReporter( reportManager, suite );
326 testNG.addListener( (Object) reporter );
327
328
329 if ( sourcePath != null )
330 {
331 testNG.setSourcePath( sourcePath );
332 }
333
334 testNG.setOutputDirectory( reportsDirectory.getAbsolutePath() );
335 }
336
337
338
339 private static TestNGReporter createTestNGReporter( RunListener reportManager, TestNgTestSuite suite )
340 {
341 try
342 {
343 Class.forName( "org.testng.internal.IResultListener" );
344 Class c = Class.forName( "org.apache.maven.surefire.testng.ConfigurationAwareTestNGReporter" );
345 try
346 {
347 Constructor ctor = c.getConstructor( new Class[] { RunListener.class, TestNgTestSuite.class } );
348 return (TestNGReporter) ctor.newInstance( reportManager, suite );
349 }
350 catch ( Exception e )
351 {
352 throw new RuntimeException( "Bug in ConfigurationAwareTestNGReporter", e );
353 }
354 }
355 catch ( ClassNotFoundException e )
356 {
357 return new TestNGReporter( reportManager );
358 }
359 }
360
361 }