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