View Javadoc
1   package org.apache.maven.surefire.booter;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.PrintStream;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  
26  import org.apache.maven.surefire.providerapi.SurefireProvider;
27  import org.apache.maven.surefire.report.ReporterException;
28  import org.apache.maven.surefire.suite.RunResult;
29  import org.apache.maven.surefire.testset.TestSetFailedException;
30  
31  import static org.apache.maven.surefire.util.ReflectionUtils.getMethod;
32  import static org.apache.maven.surefire.util.ReflectionUtils.invokeGetter;
33  import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray;
34  import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray2;
35  
36  /**
37   * Creates the surefire provider.
38   * <br>
39   *
40   * @author Kristian Rosenvold
41   */
42  public class ProviderFactory
43  {
44      private final StartupConfiguration startupConfiguration;
45  
46      private final ProviderConfiguration providerConfiguration;
47  
48      private final ClassLoader classLoader;
49  
50      private final SurefireReflector surefireReflector;
51  
52      private final Object reporterManagerFactory;
53  
54      private static final Class[] INVOKE_PARAMETERS = { Object.class };
55  
56      private static final Class[] INVOKE_EMPTY_PARAMETER_TYPES = { };
57  
58      private static final Class[] INVOKE_EMPTY_PARAMETERS = { };
59  
60      public ProviderFactory( StartupConfiguration startupConfiguration, ProviderConfiguration providerConfiguration,
61                              ClassLoader testsClassLoader, Object reporterManagerFactory )
62      {
63          this.providerConfiguration = providerConfiguration;
64          this.startupConfiguration = startupConfiguration;
65          this.surefireReflector = new SurefireReflector( testsClassLoader );
66          this.classLoader = testsClassLoader;
67          this.reporterManagerFactory = reporterManagerFactory;
68      }
69  
70      public static RunResult invokeProvider( Object testSet, ClassLoader testsClassLoader, Object factory,
71                                              ProviderConfiguration providerConfiguration, boolean insideFork,
72                                              StartupConfiguration startupConfig, boolean restoreStreams )
73          throws TestSetFailedException, InvocationTargetException
74      {
75          final PrintStream orgSystemOut = System.out;
76          final PrintStream orgSystemErr = System.err;
77          // Note that System.out/System.err are also read in the "ReporterConfiguration" instantiation
78          // in createProvider below. These are the same values as here.
79  
80          try
81          {
82              return new ProviderFactory( startupConfig, providerConfiguration, testsClassLoader, factory )
83                  .createProvider( insideFork )
84                  .invoke( testSet );
85          }
86          finally
87          {
88              if ( restoreStreams && System.getSecurityManager() == null )
89              {
90                  System.setOut( orgSystemOut );
91                  System.setErr( orgSystemErr );
92              }
93          }
94      }
95  
96      public SurefireProvider createProvider( boolean isInsideFork )
97      {
98          final Thread currentThread = Thread.currentThread();
99          final ClassLoader systemClassLoader = currentThread.getContextClassLoader();
100         currentThread.setContextClassLoader( classLoader );
101         // Note: Duplicated in ForkedBooter#createProviderInCurrentClassloader
102         Object o = surefireReflector.createBooterConfiguration( classLoader, reporterManagerFactory, isInsideFork );
103         surefireReflector.setTestSuiteDefinitionAware( o, providerConfiguration.getTestSuiteDefinition() );
104         surefireReflector.setProviderPropertiesAware( o, providerConfiguration.getProviderProperties() );
105         surefireReflector.setReporterConfigurationAware( o, providerConfiguration.getReporterConfiguration() );
106         surefireReflector.setTestClassLoaderAware( o, classLoader );
107         surefireReflector.setTestArtifactInfoAware( o, providerConfiguration.getTestArtifact() );
108         surefireReflector.setRunOrderParameters( o, providerConfiguration.getRunOrderParameters() );
109         surefireReflector.setIfDirScannerAware( o, providerConfiguration.getDirScannerParams() );
110         surefireReflector.setMainCliOptions( o, providerConfiguration.getMainCliOptions() );
111         surefireReflector.setSkipAfterFailureCount( o, providerConfiguration.getSkipAfterFailureCount() );
112         surefireReflector.setShutdown( o, providerConfiguration.getShutdown() );
113         if ( isInsideFork )
114         {
115             surefireReflector.setSystemExitTimeout( o, providerConfiguration.getSystemExitTimeout() );
116         }
117 
118         Object provider = surefireReflector.instantiateProvider( startupConfiguration.getActualClassName(), o );
119         currentThread.setContextClassLoader( systemClassLoader );
120 
121         return new ProviderProxy( provider, classLoader );
122     }
123 
124     private final class ProviderProxy
125         implements SurefireProvider
126     {
127         private final Object providerInOtherClassLoader;
128 
129         private final ClassLoader testsClassLoader;
130 
131 
132         private ProviderProxy( Object providerInOtherClassLoader, ClassLoader testsClassLoader )
133         {
134             this.providerInOtherClassLoader = providerInOtherClassLoader;
135             this.testsClassLoader = testsClassLoader;
136         }
137 
138         @Override
139         @SuppressWarnings( "unchecked" )
140         public Iterable<Class<?>> getSuites()
141         {
142             ClassLoader current = swapClassLoader( testsClassLoader );
143             try
144             {
145                 return (Iterable<Class<?>>) invokeGetter( providerInOtherClassLoader, "getSuites" );
146             }
147             finally
148             {
149                 Thread.currentThread().setContextClassLoader( current );
150             }
151         }
152 
153         @Override
154         public RunResult invoke( Object forkTestSet )
155             throws TestSetFailedException, ReporterException, InvocationTargetException
156         {
157             ClassLoader current = swapClassLoader( testsClassLoader );
158             try
159             {
160                 Method invoke = getMethod( providerInOtherClassLoader.getClass(), "invoke", INVOKE_PARAMETERS );
161                 Object result = invokeMethodWithArray2( providerInOtherClassLoader, invoke, forkTestSet );
162                 return (RunResult) surefireReflector.convertIfRunResult( result );
163             }
164             finally
165             {
166                 if ( System.getSecurityManager() == null )
167                 {
168                     Thread.currentThread().setContextClassLoader( current );
169                 }
170             }
171         }
172 
173         private ClassLoader swapClassLoader( ClassLoader newClassLoader )
174         {
175             ClassLoader current = Thread.currentThread().getContextClassLoader();
176             Thread.currentThread().setContextClassLoader( newClassLoader );
177             return current;
178         }
179 
180         @Override
181         public void cancel()
182         {
183             Class<?> providerType = providerInOtherClassLoader.getClass();
184             Method invoke = getMethod( providerType, "cancel", INVOKE_EMPTY_PARAMETER_TYPES );
185             invokeMethodWithArray( providerInOtherClassLoader, invoke, INVOKE_EMPTY_PARAMETERS );
186         }
187     }
188 }