1 package org.apache.maven.surefire.booter;
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.plugin.surefire.log.api.ConsoleLogger;
23 import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerDecorator;
24 import org.apache.maven.surefire.cli.CommandLineOption;
25 import org.apache.maven.surefire.providerapi.ProviderParameters;
26 import org.apache.maven.surefire.report.ReporterConfiguration;
27 import org.apache.maven.surefire.report.ReporterFactory;
28 import org.apache.maven.surefire.suite.RunResult;
29 import org.apache.maven.surefire.testset.DirectoryScannerParameters;
30 import org.apache.maven.surefire.testset.RunOrderParameters;
31 import org.apache.maven.surefire.testset.TestArtifactInfo;
32 import org.apache.maven.surefire.testset.TestListResolver;
33 import org.apache.maven.surefire.testset.TestRequest;
34 import org.apache.maven.surefire.util.RunOrder;
35 import org.apache.maven.surefire.util.SurefireReflectionException;
36
37 import javax.annotation.Nonnull;
38 import java.io.File;
39 import java.lang.reflect.Constructor;
40 import java.lang.reflect.InvocationHandler;
41 import java.lang.reflect.Method;
42 import java.util.ArrayList;
43 import java.util.Collection;
44 import java.util.List;
45 import java.util.Map;
46
47 import static java.util.Collections.checkedList;
48 import static org.apache.maven.surefire.util.ReflectionUtils.getConstructor;
49 import static org.apache.maven.surefire.util.ReflectionUtils.getMethod;
50 import static org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg;
51 import static org.apache.maven.surefire.util.ReflectionUtils.instantiateTwoArgs;
52 import static org.apache.maven.surefire.util.ReflectionUtils.invokeGetter;
53 import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray;
54 import static org.apache.maven.surefire.util.ReflectionUtils.invokeSetter;
55 import static org.apache.maven.surefire.util.ReflectionUtils.newInstance;
56
57
58
59
60
61
62
63
64 public class SurefireReflector
65 {
66 private final ClassLoader surefireClassLoader;
67
68 private final Class<?> reporterConfiguration;
69
70 private final Class<?> testRequest;
71
72 private final Class<?> testArtifactInfo;
73
74 private final Class<?> testArtifactInfoAware;
75
76 private final Class<?> directoryScannerParameters;
77
78 private final Class<?> runOrderParameters;
79
80 private final Class<?> directoryScannerParametersAware;
81
82 private final Class<?> testSuiteDefinitionAware;
83
84 private final Class<?> testClassLoaderAware;
85
86 private final Class<?> reporterConfigurationAware;
87
88 private final Class<?> providerPropertiesAware;
89
90 private final Class<?> runResult;
91
92 private final Class<?> booterParameters;
93
94 private final Class<?> reporterFactory;
95
96 private final Class<?> testListResolver;
97
98 private final Class<?> mainCliOptions;
99
100 private final Class<Enum> commandLineOptionsClass;
101
102 private final Class<?> shutdownAwareClass;
103
104 private final Class<Enum> shutdownClass;
105
106 @SuppressWarnings( "unchecked" )
107 public SurefireReflector( ClassLoader surefireClassLoader )
108 {
109 this.surefireClassLoader = surefireClassLoader;
110 try
111 {
112 reporterConfiguration = surefireClassLoader.loadClass( ReporterConfiguration.class.getName() );
113 testRequest = surefireClassLoader.loadClass( TestRequest.class.getName() );
114 testArtifactInfo = surefireClassLoader.loadClass( TestArtifactInfo.class.getName() );
115 testArtifactInfoAware = surefireClassLoader.loadClass( TestArtifactInfoAware.class.getName() );
116 directoryScannerParameters = surefireClassLoader.loadClass( DirectoryScannerParameters.class.getName() );
117 runOrderParameters = surefireClassLoader.loadClass( RunOrderParameters.class.getName() );
118 directoryScannerParametersAware =
119 surefireClassLoader.loadClass( DirectoryScannerParametersAware.class.getName() );
120 testSuiteDefinitionAware = surefireClassLoader.loadClass( TestRequestAware.class.getName() );
121 testClassLoaderAware = surefireClassLoader.loadClass( SurefireClassLoadersAware.class.getName() );
122 reporterConfigurationAware = surefireClassLoader.loadClass( ReporterConfigurationAware.class.getName() );
123 providerPropertiesAware = surefireClassLoader.loadClass( ProviderPropertiesAware.class.getName() );
124 reporterFactory = surefireClassLoader.loadClass( ReporterFactory.class.getName() );
125 runResult = surefireClassLoader.loadClass( RunResult.class.getName() );
126 booterParameters = surefireClassLoader.loadClass( ProviderParameters.class.getName() );
127 testListResolver = surefireClassLoader.loadClass( TestListResolver.class.getName() );
128 mainCliOptions = surefireClassLoader.loadClass( MainCliOptionsAware.class.getName() );
129 commandLineOptionsClass = (Class<Enum>) surefireClassLoader.loadClass( CommandLineOption.class.getName() );
130 shutdownAwareClass = surefireClassLoader.loadClass( ShutdownAware.class.getName() );
131 shutdownClass = (Class<Enum>) surefireClassLoader.loadClass( Shutdown.class.getName() );
132 }
133 catch ( ClassNotFoundException e )
134 {
135 throw new SurefireReflectionException( e );
136 }
137 }
138
139 public Object convertIfRunResult( Object result )
140 {
141 if ( result == null || !isRunResult( result ) )
142 {
143 return result;
144 }
145 int getCompletedCount1 = (Integer) invokeGetter( result, "getCompletedCount" );
146 int getErrors = (Integer) invokeGetter( result, "getErrors" );
147 int getSkipped = (Integer) invokeGetter( result, "getSkipped" );
148 int getFailures = (Integer) invokeGetter( result, "getFailures" );
149 return new RunResult( getCompletedCount1, getErrors, getFailures, getSkipped );
150
151 }
152
153 class ClassLoaderProxy
154 implements InvocationHandler
155 {
156 private final Object target;
157
158
159
160
161 ClassLoaderProxy( Object delegate )
162 {
163 this.target = delegate;
164 }
165
166 @Override
167 public Object invoke( Object proxy, Method method, Object[] args )
168 throws Throwable
169 {
170 Method delegateMethod = target.getClass().getMethod( method.getName(), method.getParameterTypes() );
171 return delegateMethod.invoke( target, args );
172 }
173 }
174
175 Object createTestRequest( TestRequest suiteDefinition )
176 {
177 if ( suiteDefinition == null )
178 {
179 return null;
180 }
181 else
182 {
183 Object resolver = createTestListResolver( suiteDefinition.getTestListResolver() );
184 Class<?>[] arguments = { List.class, File.class, testListResolver, int.class };
185 Constructor constructor = getConstructor( testRequest, arguments );
186 return newInstance( constructor,
187 suiteDefinition.getSuiteXmlFiles(),
188 suiteDefinition.getTestSourceDirectory(),
189 resolver,
190 suiteDefinition.getRerunFailingTestsCount() );
191 }
192 }
193
194 Object createTestListResolver( TestListResolver resolver )
195 {
196 if ( resolver == null )
197 {
198 return null;
199 }
200 else
201 {
202 Constructor constructor = getConstructor( testListResolver, String.class );
203 return newInstance( constructor, resolver.getPluginParameterTest() );
204 }
205 }
206
207 Object createDirectoryScannerParameters( DirectoryScannerParameters directoryScannerParameters )
208 {
209 if ( directoryScannerParameters == null )
210 {
211 return null;
212 }
213
214 Class<?>[] arguments = { File.class, List.class, List.class, List.class, boolean.class, String.class };
215 Constructor constructor = getConstructor( this.directoryScannerParameters, arguments );
216 return newInstance( constructor,
217 directoryScannerParameters.getTestClassesDirectory(),
218 directoryScannerParameters.getIncludes(),
219 directoryScannerParameters.getExcludes(),
220 directoryScannerParameters.getSpecificTests(),
221 directoryScannerParameters.isFailIfNoTests(),
222 RunOrder.asString( directoryScannerParameters.getRunOrder() ) );
223 }
224
225
226 Object createRunOrderParameters( RunOrderParameters runOrderParameters )
227 {
228 if ( runOrderParameters == null )
229 {
230 return null;
231 }
232
233 Class<?>[] arguments = { String.class, File.class };
234 Constructor constructor = getConstructor( this.runOrderParameters, arguments );
235 File runStatisticsFile = runOrderParameters.getRunStatisticsFile();
236 return newInstance( constructor, RunOrder.asString( runOrderParameters.getRunOrder() ), runStatisticsFile );
237 }
238
239 Object createTestArtifactInfo( TestArtifactInfo testArtifactInfo )
240 {
241 if ( testArtifactInfo == null )
242 {
243 return null;
244 }
245 Class<?>[] arguments = { String.class, String.class };
246 Constructor constructor = getConstructor( this.testArtifactInfo, arguments );
247 return newInstance( constructor, testArtifactInfo.getVersion(), testArtifactInfo.getClassifier() );
248 }
249
250 Object createReporterConfiguration( ReporterConfiguration reporterConfig )
251 {
252 Constructor constructor = getConstructor( reporterConfiguration, File.class, boolean.class );
253 return newInstance( constructor, reporterConfig.getReportsDirectory(), reporterConfig.isTrimStackTrace() );
254 }
255
256 public Object createBooterConfiguration( ClassLoader surefireClassLoader, Object factoryInstance,
257 boolean insideFork )
258 {
259 return instantiateTwoArgs( surefireClassLoader, BaseProviderFactory.class.getName(),
260 reporterFactory, factoryInstance, boolean.class, insideFork );
261 }
262
263 public Object instantiateProvider( String providerClassName, Object booterParameters )
264 {
265 return instantiateOneArg( surefireClassLoader, providerClassName, this.booterParameters, booterParameters );
266 }
267
268 public void setIfDirScannerAware( Object o, DirectoryScannerParameters dirScannerParams )
269 {
270 if ( directoryScannerParametersAware.isAssignableFrom( o.getClass() ) )
271 {
272 setDirectoryScannerParameters( o, dirScannerParams );
273 }
274 }
275
276 public void setMainCliOptions( Object o, List<CommandLineOption> options )
277 {
278 if ( mainCliOptions.isAssignableFrom( o.getClass() ) )
279 {
280 List<Enum> newOptions = checkedList( new ArrayList<Enum>( options.size() ), commandLineOptionsClass );
281 Collection<Integer> ordinals = toOrdinals( options );
282 for ( Enum e : commandLineOptionsClass.getEnumConstants() )
283 {
284 if ( ordinals.contains( e.ordinal() ) )
285 {
286 newOptions.add( e );
287 }
288 }
289 invokeSetter( o, "setMainCliOptions", List.class, newOptions );
290 }
291 }
292
293 public void setSkipAfterFailureCount( Object o, int skipAfterFailureCount )
294 {
295 invokeSetter( o, "setSkipAfterFailureCount", int.class, skipAfterFailureCount );
296 }
297
298 public void setShutdown( Object o, Shutdown shutdown )
299 {
300 if ( shutdownAwareClass.isAssignableFrom( o.getClass() ) )
301 {
302 for ( Enum e : shutdownClass.getEnumConstants() )
303 {
304 if ( shutdown.ordinal() == e.ordinal() )
305 {
306 invokeSetter( o, "setShutdown", shutdownClass, e );
307 break;
308 }
309 }
310 }
311 }
312
313 public void setSystemExitTimeout( Object o, Integer systemExitTimeout )
314 {
315 invokeSetter( o, "setSystemExitTimeout", Integer.class, systemExitTimeout );
316 }
317
318 public void setDirectoryScannerParameters( Object o, DirectoryScannerParameters dirScannerParams )
319 {
320 Object param = createDirectoryScannerParameters( dirScannerParams );
321 invokeSetter( o, "setDirectoryScannerParameters", directoryScannerParameters, param );
322 }
323
324 public void setRunOrderParameters( Object o, RunOrderParameters runOrderParameters )
325 {
326 Object param = createRunOrderParameters( runOrderParameters );
327 invokeSetter( o, "setRunOrderParameters", this.runOrderParameters, param );
328 }
329
330 public void setTestSuiteDefinitionAware( Object o, TestRequest testSuiteDefinition2 )
331 {
332 if ( testSuiteDefinitionAware.isAssignableFrom( o.getClass() ) )
333 {
334 setTestSuiteDefinition( o, testSuiteDefinition2 );
335 }
336 }
337
338 void setTestSuiteDefinition( Object o, TestRequest testSuiteDefinition1 )
339 {
340 Object param = createTestRequest( testSuiteDefinition1 );
341 invokeSetter( o, "setTestRequest", testRequest, param );
342 }
343
344 public void setProviderPropertiesAware( Object o, Map<String, String> properties )
345 {
346 if ( providerPropertiesAware.isAssignableFrom( o.getClass() ) )
347 {
348 setProviderProperties( o, properties );
349 }
350 }
351
352 void setProviderProperties( Object o, Map<String, String> providerProperties )
353 {
354 invokeSetter( o, "setProviderProperties", Map.class, providerProperties );
355 }
356
357 public void setReporterConfigurationAware( Object o, ReporterConfiguration reporterConfiguration1 )
358 {
359 if ( reporterConfigurationAware.isAssignableFrom( o.getClass() ) )
360 {
361 setReporterConfiguration( o, reporterConfiguration1 );
362 }
363 }
364
365
366 void setReporterConfiguration( Object o, ReporterConfiguration reporterConfiguration )
367 {
368 Object param = createReporterConfiguration( reporterConfiguration );
369 invokeSetter( o, "setReporterConfiguration", this.reporterConfiguration, param );
370 }
371
372 public void setTestClassLoaderAware( Object o, ClassLoader testClassLoader )
373 {
374 if ( testClassLoaderAware.isAssignableFrom( o.getClass() ) )
375 {
376 setTestClassLoader( o, testClassLoader );
377 }
378 }
379
380 void setTestClassLoader( Object o, ClassLoader testClassLoader )
381 {
382 Method setter = getMethod( o, "setClassLoaders", ClassLoader.class );
383 invokeMethodWithArray( o, setter, testClassLoader );
384 }
385
386 public void setTestArtifactInfoAware( Object o, TestArtifactInfo testArtifactInfo1 )
387 {
388 if ( testArtifactInfoAware.isAssignableFrom( o.getClass() ) )
389 {
390 setTestArtifactInfo( o, testArtifactInfo1 );
391 }
392 }
393
394 void setTestArtifactInfo( Object o, TestArtifactInfo testArtifactInfo )
395 {
396 Object param = createTestArtifactInfo( testArtifactInfo );
397 invokeSetter( o, "setTestArtifactInfo", this.testArtifactInfo, param );
398 }
399
400 private boolean isRunResult( Object o )
401 {
402 return runResult.isAssignableFrom( o.getClass() );
403 }
404
405 public Object createConsoleLogger( @Nonnull ConsoleLogger consoleLogger )
406 {
407 return createConsoleLogger( consoleLogger, surefireClassLoader );
408 }
409
410 private static Collection<Integer> toOrdinals( Collection<? extends Enum> enums )
411 {
412 Collection<Integer> ordinals = new ArrayList<>( enums.size() );
413 for ( Enum e : enums )
414 {
415 ordinals.add( e.ordinal() );
416 }
417 return ordinals;
418 }
419
420 public static Object createConsoleLogger( ConsoleLogger consoleLogger, ClassLoader cl )
421 {
422 try
423 {
424 Class<?> decoratorClass = cl.loadClass( ConsoleLoggerDecorator.class.getName() );
425 return getConstructor( decoratorClass, Object.class ).newInstance( consoleLogger );
426 }
427 catch ( Exception e )
428 {
429 throw new SurefireReflectionException( e );
430 }
431 }
432
433 }