View Javadoc

1   package org.apache.maven.surefire.testng;
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 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.NestedRuntimeException;
27  import org.apache.maven.surefire.util.internal.StringUtils;
28  import org.testng.TestNG;
29  
30  import java.io.File;
31  import java.lang.reflect.Constructor;
32  import java.lang.reflect.InvocationTargetException;
33  import java.lang.reflect.Method;
34  import java.util.List;
35  import java.util.Map;
36  
37  /**
38   * Contains utility methods for executing TestNG.
39   *
40   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
41   * @author <a href='mailto:the[dot]mindstorm[at]gmail[dot]com'>Alex Popescu</a>
42   */
43  public class TestNGExecutor
44  {
45  
46  
47      private TestNGExecutor()
48      {
49          // noop
50      }
51  
52      public static void run( Class[] testClasses, String testSourceDirectory, Map options, RunListener reportManager,
53                              TestNgTestSuite suite, File reportsDirectory, final String methodNamePattern )
54          throws TestSetFailedException
55      {
56          TestNG testng = new TestNG( true );
57  
58          applyGroupMatching( testng, options );
59          if ( !StringUtils.isBlank( methodNamePattern ) )
60          {
61              applyMethodNameFiltering( testng, methodNamePattern );
62          }
63  
64          Configurator configurator = getConfigurator( (String) options.get("testng.configurator" ) );
65          System.out.println( "Configuring TestNG with: " + configurator.getClass().getSimpleName() );
66          configurator.configure( testng, options );
67          postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory );
68          testng.setTestClasses( testClasses );
69          testng.run();
70      }
71  
72      private static void applyMethodNameFiltering( TestNG testng, String methodNamePattern )
73          throws TestSetFailedException
74      {
75          // the class is available in the testClassPath
76          String clazzName = "org.apache.maven.surefire.testng.utils.MethodSelector";
77          // looks to need a high value 
78          testng.addMethodSelector( clazzName, 10000 );
79          try
80          {
81              Class clazz = Class.forName( clazzName );
82  
83              Method method = clazz.getMethod( "setMethodName", new Class[]{ String.class } );
84              method.invoke( null, methodNamePattern );
85          }
86          catch ( ClassNotFoundException e )
87          {
88              throw new TestSetFailedException( e.getMessage(), e );
89          }
90          catch ( SecurityException e )
91          {
92              throw new TestSetFailedException( e.getMessage(), e );
93          }
94          catch ( NoSuchMethodException e )
95          {
96              throw new TestSetFailedException( e.getMessage(), e );
97          }
98          catch ( IllegalArgumentException e )
99          {
100             throw new TestSetFailedException( e.getMessage(), e );
101         }
102         catch ( IllegalAccessException e )
103         {
104             throw new TestSetFailedException( e.getMessage(), e );
105         }
106         catch ( InvocationTargetException e )
107         {
108             throw new TestSetFailedException( e.getMessage(), e );
109         }
110     }
111 
112     private static void applyGroupMatching( TestNG testng, Map options )
113         throws TestSetFailedException
114     {
115         String groups = (String) options.get( ProviderParameterNames.TESTNG_GROUPS_PROP );
116         String excludedGroups = (String) options.get( ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP );
117 
118         if ( groups == null && excludedGroups == null )
119         {
120             return;
121         }
122 
123         // the class is available in the testClassPath
124         String clazzName = "org.apache.maven.surefire.testng.utils.GroupMatcherMethodSelector";
125         // looks to need a high value
126         testng.addMethodSelector( clazzName, 9999 );
127         try
128         {
129             Class clazz = Class.forName( clazzName );
130 
131             // HORRIBLE hack, but TNG doesn't allow us to setup a method selector instance directly.
132             Method method = clazz.getMethod( "setGroups", new Class[]{ String.class, String.class } );
133             method.invoke( null, groups, excludedGroups );
134         }
135         catch ( ClassNotFoundException e )
136         {
137             throw new TestSetFailedException( e.getMessage(), e );
138         }
139         catch ( SecurityException e )
140         {
141             throw new TestSetFailedException( e.getMessage(), e );
142         }
143         catch ( NoSuchMethodException e )
144         {
145             throw new TestSetFailedException( e.getMessage(), e );
146         }
147         catch ( IllegalArgumentException e )
148         {
149             throw new TestSetFailedException( e.getMessage(), e );
150         }
151         catch ( IllegalAccessException e )
152         {
153             throw new TestSetFailedException( e.getMessage(), e );
154         }
155         catch ( InvocationTargetException e )
156         {
157             throw new TestSetFailedException( e.getMessage(), e );
158         }
159     }
160 
161     public static void run( List<String> suiteFiles, String testSourceDirectory, Map options, RunListener reportManager,
162                             TestNgTestSuite suite, File reportsDirectory )
163         throws TestSetFailedException
164     {
165         TestNG testng = new TestNG( true );
166         Configurator configurator = getConfigurator( (String) options.get("testng.configurator" ) );
167         configurator.configure( testng, options );
168         postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory );
169         testng.setTestSuites( suiteFiles );
170         testng.run();
171     }
172 
173     private static Configurator getConfigurator( String className )
174     {
175         try
176         {
177             return (Configurator) Class.forName( className ).newInstance();
178         }
179         catch ( InstantiationException e )
180         {
181             throw new RuntimeException( e );
182         }
183         catch ( IllegalAccessException e )
184         {
185             throw new RuntimeException( e );
186         }
187         catch ( ClassNotFoundException e )
188         {
189             throw new RuntimeException( e );
190         }
191     }
192 
193 
194     private static void postConfigure( TestNG testNG, String sourcePath, RunListener reportManager,
195                                        TestNgTestSuite suite, File reportsDirectory )
196         throws TestSetFailedException
197     {
198         // turn off all TestNG output
199         testNG.setVerbose( 0 );
200 
201         TestNGReporter reporter = createTestNGReporter( reportManager, suite );
202         testNG.addListener( (Object) reporter );
203 
204         // FIXME: use classifier to decide if we need to pass along the source dir (onyl for JDK14)
205         if ( sourcePath != null )
206         {
207             testNG.setSourcePath( sourcePath );
208         }
209 
210         testNG.setOutputDirectory( reportsDirectory.getAbsolutePath() );
211     }
212 
213     // If we have access to IResultListener, return a ConfigurationAwareTestNGReporter
214     // But don't cause NoClassDefFoundErrors if it isn't available; just return a regular TestNGReporter instead
215     private static TestNGReporter createTestNGReporter( RunListener reportManager, TestNgTestSuite suite )
216     {
217         try
218         {
219             Class.forName( "org.testng.internal.IResultListener" );
220             Class c = Class.forName( "org.apache.maven.surefire.testng.ConfigurationAwareTestNGReporter" );
221             try
222             {
223                 Constructor ctor = c.getConstructor( new Class[]{ RunListener.class, TestNgTestSuite.class } );
224                 return (TestNGReporter) ctor.newInstance( reportManager, suite );
225             }
226             catch ( Exception e )
227             {
228                 throw new NestedRuntimeException( "Bug in ConfigurationAwareTestNGReporter", e );
229             }
230         }
231         catch ( ClassNotFoundException e )
232         {
233             return new TestNGReporter( reportManager );
234         }
235     }
236 
237 }