1 package org.testng;
2 
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.net.URLClassLoader;
8 import java.util.ArrayList;
9 import java.util.Arrays;
10 import java.util.Collection;
11 import java.util.Enumeration;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.ServiceLoader;
15 import java.util.Set;
16 import java.util.concurrent.LinkedBlockingQueue;
17 import java.util.concurrent.TimeUnit;
18 import java.util.jar.JarEntry;
19 import java.util.jar.JarFile;
20 
21 import javax.xml.parsers.ParserConfigurationException;
22 
23 import org.testng.annotations.ITestAnnotation;
24 import org.testng.collections.Lists;
25 import org.testng.collections.Maps;
26 import org.testng.collections.Sets;
27 import org.testng.internal.ClassHelper;
28 import org.testng.internal.Configuration;
29 import org.testng.internal.DynamicGraph;
30 import org.testng.internal.IConfiguration;
31 import org.testng.internal.IPathUtils;
32 import org.testng.internal.IResultListener2;
33 import org.testng.internal.OverrideProcessor;
34 import org.testng.internal.PathUtilsFactory;
35 import org.testng.internal.SuiteRunnerMap;
36 import org.testng.internal.Utils;
37 import org.testng.internal.Version;
38 import org.testng.internal.annotations.DefaultAnnotationTransformer;
39 import org.testng.internal.annotations.IAnnotationFinder;
40 import org.testng.internal.annotations.JDK15AnnotationFinder;
41 import org.testng.internal.thread.graph.GraphThreadPoolExecutor;
42 import org.testng.internal.thread.graph.IThreadWorkerFactory;
43 import org.testng.internal.thread.graph.SuiteWorkerFactory;
44 import org.testng.junit.JUnitTestFinder;
45 import org.testng.log4testng.Logger;
46 import org.testng.remote.SuiteDispatcher;
47 import org.testng.remote.SuiteSlave;
48 import org.testng.reporters.EmailableReporter;
49 import org.testng.reporters.EmailableReporter2;
50 import org.testng.reporters.FailedReporter;
51 import org.testng.reporters.JUnitReportReporter;
52 import org.testng.reporters.SuiteHTMLReporter;
53 import org.testng.reporters.VerboseReporter;
54 import org.testng.reporters.XMLReporter;
55 import org.testng.reporters.jq.Main;
56 import org.testng.xml.Parser;
57 import org.testng.xml.XmlClass;
58 import org.testng.xml.XmlInclude;
59 import org.testng.xml.XmlMethodSelector;
60 import org.testng.xml.XmlSuite;
61 import org.testng.xml.XmlTest;
62 import org.xml.sax.SAXException;
63 
64 import com.beust.jcommander.JCommander;
65 import com.beust.jcommander.ParameterException;
66 
67 import static org.testng.internal.Utils.defaultIfStringEmpty;
68 import static org.testng.internal.Utils.isStringEmpty;
69 import static org.testng.internal.Utils.isStringNotEmpty;
70 
71 /**
72  * This class is the main entry point for running tests in the TestNG framework.
73  * Users can create their own TestNG object and invoke it in many different
74  * ways:
75  * <ul>
76  * <li>On an existing testng.xml
77  * <li>On a synthetic testng.xml, created entirely from Java
78  * <li>By directly setting the test classes
79  * </ul>
80  * You can also define which groups to include or exclude, assign parameters, etc...
81  * <P/>
82  * The command line parameters are:
83  * <UL>
84  *  <LI>-d <TT>outputdir</TT>: specify the output directory</LI>
85  *  <LI>-testclass <TT>class_name</TT>: specifies one or several class names </li>
86  *  <LI>-testjar <TT>jar_name</TT>: specifies the jar containing the tests</LI>
87  *  <LI>-sourcedir <TT>src1;src2</TT>: ; separated list of source directories
88  *    (used only when javadoc annotations are used)</LI>
89  *  <LI>-target</LI>
90  *  <LI>-groups</LI>
91  *  <LI>-testrunfactory</LI>
92  *  <LI>-listener</LI>
93  * </UL>
94  * <P/>
95  * Please consult documentation for more details.
96  *
97  * FIXME: should support more than simple paths for suite xmls
98  *
99  * @see #usage()
100  *
101  * @author <a href = "mailto:cedric&#64;beust.com">Cedric Beust</a>
102  */
103 public class TestNG {
104 
105   /** This class' log4testng Logger. */
106   private static final Logger LOGGER = Logger.getLogger(TestNG.class);
107 
108   /** The default name for a suite launched from the command line */
109   public static final String DEFAULT_COMMAND_LINE_SUITE_NAME = "Command line suite";
110 
111   /** The default name for a test launched from the command line */
112   public static final String DEFAULT_COMMAND_LINE_TEST_NAME = "Command line test";
113 
114   /** The default name of the result's output directory (keep public, used by Eclipse). */
115   public static final String DEFAULT_OUTPUTDIR = "test-output";
116 
117   /** System properties */
118   public static final String SHOW_TESTNG_STACK_FRAMES = "testng.show.stack.frames";
119   public static final String TEST_CLASSPATH = "testng.test.classpath";
120 
121   private static TestNG m_instance;
122 
123   private static JCommander m_jCommander;
124 
125   private List<String> m_commandLineMethods;
126   protected List<XmlSuite> m_suites = Lists.newArrayList();
127   private List<XmlSuite> m_cmdlineSuites;
128   private String m_outputDir = DEFAULT_OUTPUTDIR;
129 
130   private String[] m_includedGroups;
131   private String[] m_excludedGroups;
132 
133   private Boolean m_isJUnit = XmlSuite.DEFAULT_JUNIT;
134   private Boolean m_isMixed = XmlSuite.DEFAULT_MIXED;
135   protected boolean m_useDefaultListeners = true;
136 
137   private ITestRunnerFactory m_testRunnerFactory;
138 
139   // These listeners can be overridden from the command line
140   private List<IClassListener> m_classListeners = Lists.newArrayList();
141   private List<ITestListener> m_testListeners = Lists.newArrayList();
142   private List<ISuiteListener> m_suiteListeners = Lists.newArrayList();
143   private Set<IReporter> m_reporters = Sets.newHashSet();
144 
145   protected static final int HAS_FAILURE = 1;
146   protected static final int HAS_SKIPPED = 2;
147   protected static final int HAS_FSP = 4;
148   protected static final int HAS_NO_TEST = 8;
149 
150   public static final Integer DEFAULT_VERBOSE = 1;
151 
152   private int m_status;
153   private boolean m_hasTests= false;
154 
155   private String m_slavefileName = null;
156   private String m_masterfileName = null;
157 
158   // Command line suite parameters
159   private int m_threadCount;
160   private boolean m_useThreadCount;
161   private XmlSuite.ParallelMode m_parallelMode = XmlSuite.ParallelMode.FALSE;
162   private String m_configFailurePolicy;
163   private Class[] m_commandLineTestClasses;
164 
165   private String m_defaultSuiteName=DEFAULT_COMMAND_LINE_SUITE_NAME;
166   private String m_defaultTestName=DEFAULT_COMMAND_LINE_TEST_NAME;
167 
168   private Map<String, Integer> m_methodDescriptors = Maps.newHashMap();
169 
170   private ITestObjectFactory m_objectFactory;
171 
172   private List<IInvokedMethodListener> m_invokedMethodListeners = Lists.newArrayList();
173 
174   private Integer m_dataProviderThreadCount = null;
175 
176   private String m_jarPath;
177   /** The path of the testng.xml file inside the jar file */
178   private String m_xmlPathInJar = CommandLineArgs.XML_PATH_IN_JAR_DEFAULT;
179 
180   private List<String> m_stringSuites = Lists.newArrayList();
181 
182   private IHookable m_hookable;
183   private IConfigurable m_configurable;
184 
185   protected long m_end;
186   protected long m_start;
187 
188   private List<IExecutionListener> m_executionListeners = Lists.newArrayList();
189 
190   private List<IAlterSuiteListener> m_alterSuiteListeners= Lists.newArrayList();
191 
192   private boolean m_isInitialized = false;
193 
194   private IPathUtils m_pathUtils = PathUtilsFactory.newInstance();
195 
196   /**
197    * Default constructor. Setting also usage of default listeners/reporters.
198    */
TestNG()199   public TestNG() {
200     init(true);
201   }
202 
203   /**
204    * Used by maven2 to have 0 output of any kind come out
205    * of testng.
206    * @param useDefaultListeners Whether or not any default reports
207    * should be added to tests.
208    */
TestNG(boolean useDefaultListeners)209   public TestNG(boolean useDefaultListeners) {
210     init(useDefaultListeners);
211   }
212 
init(boolean useDefaultListeners)213   private void init(boolean useDefaultListeners) {
214     m_instance = this;
215 
216     m_useDefaultListeners = useDefaultListeners;
217     m_configuration = new Configuration();
218   }
219 
getStatus()220   public int getStatus() {
221     return m_status;
222   }
223 
setStatus(int status)224   private void setStatus(int status) {
225     m_status |= status;
226   }
227 
228   /**
229    * Sets the output directory where the reports will be created.
230    * @param outputdir The directory.
231    */
setOutputDirectory(final String outputdir)232   public void setOutputDirectory(final String outputdir) {
233     if (isStringNotEmpty(outputdir)) {
234       m_outputDir = outputdir;
235     }
236   }
237 
238   /**
239    * If this method is passed true before run(), the default listeners
240    * will not be used.
241    * <ul>
242    * <li>org.testng.reporters.TestHTMLReporter
243    * <li>org.testng.reporters.JUnitXMLReporter
244    * <li>org.testng.reporters.XMLReporter
245    * </ul>
246    *
247    * @see org.testng.reporters.TestHTMLReporter
248    * @see org.testng.reporters.JUnitXMLReporter
249    * @see org.testng.reporters.XMLReporter
250    */
setUseDefaultListeners(boolean useDefaultListeners)251   public void setUseDefaultListeners(boolean useDefaultListeners) {
252     m_useDefaultListeners = useDefaultListeners;
253   }
254 
255   /**
256    * Sets a jar containing a testng.xml file.
257    *
258    * @param jarPath
259    */
setTestJar(String jarPath)260   public void setTestJar(String jarPath) {
261     m_jarPath = jarPath;
262   }
263 
264   /**
265    * Sets the path to the XML file in the test jar file.
266    */
setXmlPathInJar(String xmlPathInJar)267   public void setXmlPathInJar(String xmlPathInJar) {
268     m_xmlPathInJar = xmlPathInJar;
269   }
270 
initializeSuitesAndJarFile()271   public void initializeSuitesAndJarFile() {
272     // The Eclipse plug-in (RemoteTestNG) might have invoked this method already
273     // so don't initialize suites twice.
274     if (m_isInitialized) {
275       return;
276     }
277 
278     m_isInitialized = true;
279     if (m_suites.size() > 0) {
280     	//to parse the suite files (<suite-file>), if any
281     	for (XmlSuite s: m_suites) {
282         for (String suiteFile : s.getSuiteFiles()) {
283             try {
284                 Collection<XmlSuite> childSuites = getParser(m_pathUtils.getSuiteNormalizedPath(s, suiteFile)).parse();
285                 for (XmlSuite cSuite : childSuites){
286                     cSuite.setParentSuite(s);
287                     s.getChildSuites().add(cSuite);
288                 }
289             } catch (ParserConfigurationException | IOException | SAXException e) {
290                 e.printStackTrace(System.out);
291             }
292         }
293 
294     	}
295       return;
296     }
297 
298     //
299     // Parse the suites that were passed on the command line
300     //
301     for (String suitePath : m_stringSuites) {
302       if(LOGGER.isDebugEnabled()) {
303         LOGGER.debug("suiteXmlPath: \"" + suitePath + "\"");
304       }
305       try {
306         Collection<XmlSuite> allSuites = getParser(suitePath).parse();
307 
308         for (XmlSuite s : allSuites) {
309           // If test names were specified, only run these test names
310           if (m_testNames != null) {
311             m_suites.add(extractTestNames(s, m_testNames));
312           }
313           else {
314             m_suites.add(s);
315           }
316         }
317       }
318       catch(SAXException | ParserConfigurationException | IOException e) {
319         e.printStackTrace(System.out);
320       } catch(Exception ex) {
321         // Probably a Yaml exception, unnest it
322         Throwable t = ex;
323         while (t.getCause() != null) t = t.getCause();
324 //        t.printStackTrace();
325         if (t instanceof TestNGException) throw (TestNGException) t;
326         else throw new TestNGException(t);
327       }
328     }
329 
330     //
331     // jar path
332     //
333     // If suites were passed on the command line, they take precedence over the suite file
334     // inside that jar path
335     if (m_jarPath != null && m_stringSuites.size() > 0) {
336       StringBuilder suites = new StringBuilder();
337       for (String s : m_stringSuites) {
338         suites.append(s);
339       }
340       Utils.log("TestNG", 2, "Ignoring the XML file inside " + m_jarPath + " and using "
341           + suites + " instead");
342       return;
343     }
344     if (isStringEmpty(m_jarPath)) {
345       return;
346     }
347 
348     // We have a jar file and no XML file was specified: try to find an XML file inside the jar
349     File jarFile = new File(m_jarPath);
350 
351     try {
352 
353       Utils.log("TestNG", 2, "Trying to open jar file:" + jarFile);
354 
355       boolean foundTestngXml = false;
356       List<String> classes = Lists.newArrayList();
357       try (JarFile jf = new JarFile(jarFile)) {
358 //      System.out.println("   result: " + jf);
359         Enumeration<JarEntry> entries = jf.entries();
360         while (entries.hasMoreElements()) {
361           JarEntry je = entries.nextElement();
362           if (je.getName().equals(m_xmlPathInJar)) {
363             Parser parser = getParser(jf.getInputStream(je));
364             Collection<XmlSuite> suites = parser.parse();
365             for (XmlSuite suite : suites) {
366               // If test names were specified, only run these test names
367               if (m_testNames != null) {
368                 m_suites.add(extractTestNames(suite, m_testNames));
369               } else {
370                 m_suites.add(suite);
371               }
372             }
373 
374             foundTestngXml = true;
375             break;
376           } else if (je.getName().endsWith(".class")) {
377             int n = je.getName().length() - ".class".length();
378             classes.add(je.getName().replace("/", ".").substring(0, n));
379           }
380         }
381       }
382       if (! foundTestngXml) {
383         Utils.log("TestNG", 1,
384             "Couldn't find the " + m_xmlPathInJar + " in the jar file, running all the classes");
385         XmlSuite xmlSuite = new XmlSuite();
386         xmlSuite.setVerbose(0);
387         xmlSuite.setName("Jar suite");
388         XmlTest xmlTest = new XmlTest(xmlSuite);
389         List<XmlClass> xmlClasses = Lists.newArrayList();
390         for (String cls : classes) {
391           XmlClass xmlClass = new XmlClass(cls);
392           xmlClasses.add(xmlClass);
393         }
394         xmlTest.setXmlClasses(xmlClasses);
395         m_suites.add(xmlSuite);
396       }
397     }
398     catch(ParserConfigurationException | IOException | SAXException ex) {
399       ex.printStackTrace();
400     }
401   }
402 
getParser(String path)403   private Parser getParser(String path) {
404     Parser result = new Parser(path);
405     initProcessor(result);
406     return result;
407   }
408 
getParser(InputStream is)409   private Parser getParser(InputStream is) {
410     Parser result = new Parser(is);
411     initProcessor(result);
412     return result;
413   }
414 
initProcessor(Parser result)415   private void initProcessor(Parser result) {
416     result.setPostProcessor(new OverrideProcessor(m_includedGroups, m_excludedGroups));
417   }
418 
419   /**
420    * If the XmlSuite contains at least one test named as testNames, return
421    * an XmlSuite that's made only of these tests, otherwise, return the
422    * original suite.
423    */
extractTestNames(XmlSuite s, List<String> testNames)424   private static XmlSuite extractTestNames(XmlSuite s, List<String> testNames) {
425     extractTestNamesFromChildSuites(s, testNames);
426 
427     List<XmlTest> tests = Lists.newArrayList();
428     for (XmlTest xt : s.getTests()) {
429       for (String tn : testNames) {
430         if (xt.getName().equals(tn)) {
431           tests.add(xt);
432         }
433       }
434     }
435 
436     if (tests.size() == 0) {
437       return s;
438     }
439     else {
440       XmlSuite result = (XmlSuite) s.clone();
441       result.getTests().clear();
442       result.getTests().addAll(tests);
443       return result;
444     }
445   }
446 
extractTestNamesFromChildSuites(XmlSuite s, List<String> testNames)447   private static void extractTestNamesFromChildSuites(XmlSuite s, List<String> testNames) {
448     List<XmlSuite> childSuites = s.getChildSuites();
449     for (int i = 0; i < childSuites.size(); i++) {
450       XmlSuite child = childSuites.get(i);
451       XmlSuite extracted = extractTestNames(child, testNames);
452       // if a new xml suite is created, which means some tests was extracted, then we replace the child
453       if (extracted != child) {
454         childSuites.set(i, extracted);
455       }
456     }
457   }
458 
459   /**
460    * Define the number of threads in the thread pool.
461    */
setThreadCount(int threadCount)462   public void setThreadCount(int threadCount) {
463     if(threadCount < 1) {
464       exitWithError("Cannot use a threadCount parameter less than 1; 1 > " + threadCount);
465     }
466 
467     m_threadCount = threadCount;
468     m_useThreadCount = true;
469   }
470 
471   /**
472    * Define whether this run will be run in parallel mode.
473    * @deprecated Use #setParallel(XmlSuite.ParallelMode) instead
474    */
475   @Deprecated
setParallel(String parallel)476   public void setParallel(String parallel) {
477     if (parallel == null) {
478       setParallel(XmlSuite.ParallelMode.FALSE);
479     } else {
480       setParallel(XmlSuite.ParallelMode.getValidParallel(parallel));
481     }
482   }
483 
setParallel(XmlSuite.ParallelMode parallel)484   public void setParallel(XmlSuite.ParallelMode parallel) {
485     m_parallelMode = parallel;
486   }
487 
setCommandLineSuite(XmlSuite suite)488   public void setCommandLineSuite(XmlSuite suite) {
489     m_cmdlineSuites = Lists.newArrayList();
490     m_cmdlineSuites.add(suite);
491     m_suites.add(suite);
492   }
493 
494   /**
495    * Set the test classes to be run by this TestNG object.  This method
496    * will create a dummy suite that will wrap these classes called
497    * "Command Line Test".
498    * <p/>
499    * If used together with threadCount, parallel, groups, excludedGroups than this one must be set first.
500    *
501    * @param classes An array of classes that contain TestNG annotations.
502    */
setTestClasses(Class[] classes)503   public void setTestClasses(Class[] classes) {
504     m_suites.clear();
505     m_commandLineTestClasses = classes;
506   }
507 
508   /**
509    * Given a string com.example.Foo.f1, return an array where [0] is the class and [1]
510    * is the method.
511    */
splitMethod(String m)512   private String[] splitMethod(String m) {
513     int index = m.lastIndexOf(".");
514     if (index < 0) {
515       throw new TestNGException("Bad format for command line method:" + m
516           + ", expected <class>.<method>");
517     }
518 
519     return new String[] { m.substring(0, index), m.substring(index + 1).replaceAll("\\*", "\\.\\*") };
520   }
521 
522   /**
523    * @return a list of XmlSuite objects that represent the list of classes and methods passed
524    * in parameter.
525    *
526    * @param commandLineMethods a string with the form "com.example.Foo.f1,com.example.Bar.f2"
527    */
createCommandLineSuitesForMethods(List<String> commandLineMethods)528   private List<XmlSuite> createCommandLineSuitesForMethods(List<String> commandLineMethods) {
529     //
530     // Create the <classes> tag
531     //
532     Set<Class> classes = Sets.newHashSet();
533     for (String m : commandLineMethods) {
534       Class c = ClassHelper.forName(splitMethod(m)[0]);
535       if (c != null) {
536           classes.add(c);
537       }
538     }
539 
540     List<XmlSuite> result = createCommandLineSuitesForClasses(classes.toArray(new Class[0]));
541 
542     //
543     // Add the method tags
544     //
545     List<XmlClass> xmlClasses = Lists.newArrayList();
546     for (XmlSuite s : result) {
547         for (XmlTest t : s.getTests()) {
548             xmlClasses.addAll(t.getClasses());
549         }
550     }
551 
552     for (XmlClass xc : xmlClasses) {
553       for (String m : commandLineMethods) {
554         String[] split = splitMethod(m);
555         String className = split[0];
556         if (xc.getName().equals(className)) {
557           XmlInclude includedMethod = new XmlInclude(split[1]);
558           xc.getIncludedMethods().add(includedMethod);
559         }
560       }
561     }
562 
563     return result;
564   }
565 
createCommandLineSuitesForClasses(Class[] classes)566   private List<XmlSuite> createCommandLineSuitesForClasses(Class[] classes) {
567     //
568     // See if any of the classes has an xmlSuite or xmlTest attribute.
569     // If it does, create the appropriate XmlSuite, otherwise, create
570     // the default one
571     //
572     XmlClass[] xmlClasses = Utils.classesToXmlClasses(classes);
573     Map<String, XmlSuite> suites = Maps.newHashMap();
574     IAnnotationFinder finder = m_configuration.getAnnotationFinder();
575 
576     for (int i = 0; i < classes.length; i++) {
577       Class c = classes[i];
578       ITestAnnotation test = finder.findAnnotation(c, ITestAnnotation.class);
579       String suiteName = getDefaultSuiteName();
580       String testName = getDefaultTestName();
581       boolean isJUnit = false;
582       if (test != null) {
583         suiteName = defaultIfStringEmpty(test.getSuiteName(), suiteName);
584         testName = defaultIfStringEmpty(test.getTestName(), testName);
585       } else {
586         if (m_isMixed && JUnitTestFinder.isJUnitTest(c)) {
587           isJUnit = true;
588           testName = c.getName();
589         }
590       }
591       XmlSuite xmlSuite = suites.get(suiteName);
592       if (xmlSuite == null) {
593         xmlSuite = new XmlSuite();
594         xmlSuite.setName(suiteName);
595         suites.put(suiteName, xmlSuite);
596       }
597 
598       if (m_dataProviderThreadCount != null) {
599         xmlSuite.setDataProviderThreadCount(m_dataProviderThreadCount);
600       }
601       XmlTest xmlTest = null;
602       for (XmlTest xt  : xmlSuite.getTests()) {
603         if (xt.getName().equals(testName)) {
604           xmlTest = xt;
605           break;
606         }
607       }
608 
609       if (xmlTest == null) {
610         xmlTest = new XmlTest(xmlSuite);
611         xmlTest.setName(testName);
612         xmlTest.setJUnit(isJUnit);
613       }
614 
615       xmlTest.getXmlClasses().add(xmlClasses[i]);
616     }
617 
618     return new ArrayList<>(suites.values());
619   }
620 
addMethodSelector(String className, int priority)621   public void addMethodSelector(String className, int priority) {
622     m_methodDescriptors.put(className, priority);
623   }
624 
625   /**
626    * Set the suites file names to be run by this TestNG object. This method tries to load and
627    * parse the specified TestNG suite xml files. If a file is missing, it is ignored.
628    *
629    * @param suites A list of paths to one more XML files defining the tests.  For example:
630    *
631    * <pre>
632    * TestNG tng = new TestNG();
633    * List<String> suites = Lists.newArrayList();
634    * suites.add("c:/tests/testng1.xml");
635    * suites.add("c:/tests/testng2.xml");
636    * tng.setTestSuites(suites);
637    * tng.run();
638    * </pre>
639    */
setTestSuites(List<String> suites)640   public void setTestSuites(List<String> suites) {
641     m_stringSuites = suites;
642   }
643 
644   /**
645    * Specifies the XmlSuite objects to run.
646    * @param suites
647    * @see org.testng.xml.XmlSuite
648    */
setXmlSuites(List<XmlSuite> suites)649   public void setXmlSuites(List<XmlSuite> suites) {
650     m_suites = suites;
651   }
652 
653   /**
654    * Define which groups will be excluded from this run.
655    *
656    * @param groups A list of group names separated by a comma.
657    */
setExcludedGroups(String groups)658   public void setExcludedGroups(String groups) {
659     m_excludedGroups = Utils.split(groups, ",");
660   }
661 
662 
663   /**
664    * Define which groups will be included from this run.
665    *
666    * @param groups A list of group names separated by a comma.
667    */
setGroups(String groups)668   public void setGroups(String groups) {
669     m_includedGroups = Utils.split(groups, ",");
670   }
671 
672 
setTestRunnerFactoryClass(Class testRunnerFactoryClass)673   private void setTestRunnerFactoryClass(Class testRunnerFactoryClass) {
674     setTestRunnerFactory((ITestRunnerFactory) ClassHelper.newInstance(testRunnerFactoryClass));
675   }
676 
677 
setTestRunnerFactory(ITestRunnerFactory itrf)678   protected void setTestRunnerFactory(ITestRunnerFactory itrf) {
679     m_testRunnerFactory= itrf;
680   }
681 
setObjectFactory(Class c)682   public void setObjectFactory(Class c) {
683     m_objectFactory = (ITestObjectFactory) ClassHelper.newInstance(c);
684   }
685 
setObjectFactory(ITestObjectFactory factory)686   public void setObjectFactory(ITestObjectFactory factory) {
687     m_objectFactory = factory;
688   }
689 
690   /**
691    * Define which listeners to user for this run.
692    *
693    * @param classes A list of classes, which must be either ISuiteListener,
694    * ITestListener or IReporter
695    */
setListenerClasses(List<Class> classes)696   public void setListenerClasses(List<Class> classes) {
697     for (Class cls: classes) {
698       addListener(ClassHelper.newInstance(cls));
699     }
700   }
701 
addListener(Object listener)702   public void addListener(Object listener) {
703     if (! (listener instanceof ITestNGListener))
704     {
705       exitWithError("Listener " + listener
706           + " must be one of ITestListener, ISuiteListener, IReporter, "
707           + " IAnnotationTransformer, IMethodInterceptor or IInvokedMethodListener");
708     }
709     else {
710       if (listener instanceof ISuiteListener) {
711         addListener((ISuiteListener) listener);
712       }
713       if (listener instanceof ITestListener) {
714         addListener((ITestListener) listener);
715       }
716       if (listener instanceof IClassListener) {
717         addListener((IClassListener) listener);
718       }
719       if (listener instanceof IReporter) {
720         addListener((IReporter) listener);
721       }
722       if (listener instanceof IAnnotationTransformer) {
723         setAnnotationTransformer((IAnnotationTransformer) listener);
724       }
725       if (listener instanceof IMethodInterceptor) {
726         m_methodInterceptors.add((IMethodInterceptor) listener);
727       }
728       if (listener instanceof IInvokedMethodListener) {
729         addInvokedMethodListener((IInvokedMethodListener) listener);
730       }
731       if (listener instanceof IHookable) {
732         setHookable((IHookable) listener);
733       }
734       if (listener instanceof IConfigurable) {
735         setConfigurable((IConfigurable) listener);
736       }
737       if (listener instanceof IExecutionListener) {
738         addExecutionListener((IExecutionListener) listener);
739       }
740       if (listener instanceof IConfigurationListener) {
741         getConfiguration().addConfigurationListener((IConfigurationListener) listener);
742       }
743       if (listener instanceof IAlterSuiteListener) {
744         addAlterSuiteListener((IAlterSuiteListener) listener);
745       }
746     }
747   }
748 
addListener(IInvokedMethodListener listener)749   public void addListener(IInvokedMethodListener listener) {
750     m_invokedMethodListeners.add(listener);
751   }
752 
addListener(ISuiteListener listener)753   public void addListener(ISuiteListener listener) {
754     if (null != listener) {
755       m_suiteListeners.add(listener);
756     }
757   }
758 
addListener(ITestListener listener)759   public void addListener(ITestListener listener) {
760     if (null != listener) {
761       m_testListeners.add(listener);
762     }
763   }
764 
addListener(IClassListener listener)765   public void addListener(IClassListener listener) {
766     if (null != listener) {
767       m_classListeners.add(listener);
768     }
769   }
770 
addListener(IReporter listener)771   public void addListener(IReporter listener) {
772     if (null != listener) {
773       m_reporters.add(listener);
774     }
775   }
776 
addInvokedMethodListener(IInvokedMethodListener listener)777   public void addInvokedMethodListener(IInvokedMethodListener listener) {
778     m_invokedMethodListeners.add(listener);
779   }
780 
getReporters()781   public Set<IReporter> getReporters() {
782     return m_reporters;
783   }
784 
getTestListeners()785   public List<ITestListener> getTestListeners() {
786     return m_testListeners;
787   }
788 
getSuiteListeners()789   public List<ISuiteListener> getSuiteListeners() {
790     return m_suiteListeners;
791   }
792 
793   /** If m_verbose gets set, it will override the verbose setting in testng.xml */
794   private Integer m_verbose = null;
795 
796   private final IAnnotationTransformer m_defaultAnnoProcessor = new DefaultAnnotationTransformer();
797   private IAnnotationTransformer m_annotationTransformer = m_defaultAnnoProcessor;
798 
799   private Boolean m_skipFailedInvocationCounts = false;
800 
801   private List<IMethodInterceptor> m_methodInterceptors = new ArrayList<IMethodInterceptor>();
802 
803   /** The list of test names to run from the given suite */
804   private List<String> m_testNames;
805 
806   private Integer m_suiteThreadPoolSize = CommandLineArgs.SUITE_THREAD_POOL_SIZE_DEFAULT;
807 
808   private boolean m_randomizeSuites = Boolean.FALSE;
809 
810   private boolean m_preserveOrder = false;
811   private Boolean m_groupByInstances;
812 
813   private IConfiguration m_configuration;
814 
815   /**
816    * Sets the level of verbosity. This value will override the value specified
817    * in the test suites.
818    *
819    * @param verbose the verbosity level (0 to 10 where 10 is most detailed)
820    * Actually, this is a lie:  you can specify -1 and this will put TestNG
821    * in debug mode (no longer slicing off stack traces and all).
822    */
setVerbose(int verbose)823   public void setVerbose(int verbose) {
824     m_verbose = verbose;
825   }
826 
initializeCommandLineSuites()827   private void initializeCommandLineSuites() {
828     if (m_commandLineTestClasses != null || m_commandLineMethods != null) {
829       if (null != m_commandLineMethods) {
830         m_cmdlineSuites = createCommandLineSuitesForMethods(m_commandLineMethods);
831       }
832       else {
833         m_cmdlineSuites = createCommandLineSuitesForClasses(m_commandLineTestClasses);
834       }
835 
836       for (XmlSuite s : m_cmdlineSuites) {
837         for (XmlTest t : s.getTests()) {
838           t.setPreserveOrder(String.valueOf(m_preserveOrder));
839         }
840         m_suites.add(s);
841         if (m_groupByInstances != null) {
842           s.setGroupByInstances(m_groupByInstances);
843         }
844       }
845     }
846   }
847 
initializeCommandLineSuitesParams()848   private void initializeCommandLineSuitesParams() {
849     if(null == m_cmdlineSuites) {
850       return;
851     }
852 
853     for (XmlSuite s : m_cmdlineSuites) {
854       if(m_useThreadCount) {
855         s.setThreadCount(m_threadCount);
856       }
857       s.setParallel(m_parallelMode);
858       if(m_configFailurePolicy != null) {
859         s.setConfigFailurePolicy(m_configFailurePolicy.toString());
860       }
861     }
862 
863   }
864 
initializeCommandLineSuitesGroups()865   private void initializeCommandLineSuitesGroups() {
866     // If groups were specified on the command line, they should override groups
867     // specified in the XML file
868     boolean hasIncludedGroups = null != m_includedGroups && m_includedGroups.length > 0;
869     boolean hasExcludedGroups = null != m_excludedGroups && m_excludedGroups.length > 0;
870     List<XmlSuite> suites = m_cmdlineSuites != null ? m_cmdlineSuites : m_suites;
871     if (hasIncludedGroups || hasExcludedGroups) {
872       for (XmlSuite s : suites) {
873         //set on each test, instead of just the first one of the suite
874         for (XmlTest t : s.getTests()) {
875           if(hasIncludedGroups) {
876             t.setIncludedGroups(Arrays.asList(m_includedGroups));
877           }
878           if(hasExcludedGroups) {
879             t.setExcludedGroups(Arrays.asList(m_excludedGroups));
880           }
881         }
882       }
883     }
884   }
addReporter(Class<? extends IReporter> r)885   private void addReporter(Class<? extends IReporter> r) {
886     m_reporters.add(ClassHelper.newInstance(r));
887   }
888 
initializeDefaultListeners()889   private void initializeDefaultListeners() {
890     m_testListeners.add(new ExitCodeListener(this));
891 
892     if (m_useDefaultListeners) {
893       addReporter(SuiteHTMLReporter.class);
894       addReporter(Main.class);
895       addReporter(FailedReporter.class);
896       addReporter(XMLReporter.class);
897       if (System.getProperty("oldTestngEmailableReporter") != null) {
898         addReporter(EmailableReporter.class);
899       } else if (System.getProperty("noEmailableReporter") == null) {
900         addReporter(EmailableReporter2.class);
901       }
902       addReporter(JUnitReportReporter.class);
903       if (m_verbose != null && m_verbose > 4) {
904         addListener(new VerboseReporter("[TestNG] "));
905       }
906     }
907   }
908 
initializeConfiguration()909   private void initializeConfiguration() {
910     ITestObjectFactory factory = m_objectFactory;
911     //
912     // Install the listeners found in ServiceLoader (or use the class
913     // loader for tests, if specified).
914     //
915     addServiceLoaderListeners();
916 
917     //
918     // Install the listeners found in the suites
919     //
920     for (XmlSuite s : m_suites) {
921       for (String listenerName : s.getListeners()) {
922         Class<?> listenerClass = ClassHelper.forName(listenerName);
923 
924         // If specified listener does not exist, a TestNGException will be thrown
925         if(listenerClass == null) {
926           throw new TestNGException("Listener " + listenerName
927               + " was not found in project's classpath");
928         }
929 
930         Object listener = ClassHelper.newInstance(listenerClass);
931         addListener(listener);
932       }
933 
934       //
935       // Install the method selectors
936       //
937       for (XmlMethodSelector methodSelector : s.getMethodSelectors() ) {
938         addMethodSelector(methodSelector.getClassName(), methodSelector.getPriority());
939       }
940 
941       //
942       // Find if we have an object factory
943       //
944       if (s.getObjectFactory() != null) {
945         if (factory == null) {
946           factory = s.getObjectFactory();
947         } else {
948           throw new TestNGException("Found more than one object-factory tag in your suites");
949         }
950       }
951     }
952 
953     m_configuration.setAnnotationFinder(new JDK15AnnotationFinder(getAnnotationTransformer()));
954     m_configuration.setHookable(m_hookable);
955     m_configuration.setConfigurable(m_configurable);
956     m_configuration.setObjectFactory(factory);
957   }
958 
959   /**
960    * Using reflection to remain Java 5 compliant.
961    */
addServiceLoaderListeners()962   private void addServiceLoaderListeners() {
963       Iterable<ITestNGListener> loader = m_serviceLoaderClassLoader != null ?
964           ServiceLoader.load(ITestNGListener.class, m_serviceLoaderClassLoader)
965           : ServiceLoader.load(ITestNGListener.class);
966       for (ITestNGListener l : loader) {
967         Utils.log("[TestNG]", 2, "Adding ServiceLoader listener:" + l);
968         addListener(l);
969         addServiceLoaderListener(l);
970       }
971   }
972 
973   /**
974    * Before suites are executed, do a sanity check to ensure all required
975    * conditions are met. If not, throw an exception to stop test execution
976    *
977    * @throws TestNGException if the sanity check fails
978    */
sanityCheck()979   private void sanityCheck() {
980     checkTestNames(m_suites);
981     checkSuiteNames(m_suites);
982   }
983 
984   /**
985    * Ensure that two XmlTest within the same XmlSuite don't have the same name
986    */
checkTestNames(List<XmlSuite> suites)987   private void checkTestNames(List<XmlSuite> suites) {
988     for (XmlSuite suite : suites) {
989       Set<String> testNames = Sets.newHashSet();
990       for (XmlTest test : suite.getTests()) {
991         if (testNames.contains(test.getName())) {
992           throw new TestNGException("Two tests in the same suite "
993               + "cannot have the same name: " + test.getName());
994         } else {
995           testNames.add(test.getName());
996         }
997       }
998       checkTestNames(suite.getChildSuites());
999     }
1000   }
1001 
1002   /**
1003    * Ensure that two XmlSuite don't have the same name
1004    * Otherwise will be clash in SuiteRunnerMap
1005    * See issue #302
1006    */
checkSuiteNames(List<XmlSuite> suites)1007   private void checkSuiteNames(List<XmlSuite> suites) {
1008     checkSuiteNamesInternal(suites, Sets.<String>newHashSet());
1009   }
1010 
checkSuiteNamesInternal(List<XmlSuite> suites, Set<String> names)1011   private void checkSuiteNamesInternal(List<XmlSuite> suites, Set<String> names) {
1012     for (XmlSuite suite : suites) {
1013       final String name = suite.getName();
1014 
1015       int count = 0;
1016       String tmpName = name;
1017       while (names.contains(tmpName)) {
1018         tmpName = name + " (" + count++ + ")";
1019       }
1020 
1021       if (count > 0) {
1022         suite.setName(tmpName);
1023         names.add(tmpName);
1024       } else {
1025         names.add(name);
1026       }
1027 
1028       names.add(name);
1029       checkSuiteNamesInternal(suite.getChildSuites(), names);
1030     }
1031   }
1032 
1033   /**
1034    * Run TestNG.
1035    */
run()1036   public void run() {
1037     initializeSuitesAndJarFile();
1038     initializeConfiguration();
1039     initializeDefaultListeners();
1040     initializeCommandLineSuites();
1041     initializeCommandLineSuitesParams();
1042     initializeCommandLineSuitesGroups();
1043 
1044     sanityCheck();
1045 
1046     List<ISuite> suiteRunners = null;
1047 
1048     runSuiteAlterationListeners();
1049     runExecutionListeners(true /* start */);
1050 
1051     m_start = System.currentTimeMillis();
1052 
1053     //
1054     // Slave mode
1055     //
1056     if (m_slavefileName != null) {
1057        SuiteSlave slave = new SuiteSlave( m_slavefileName, this );
1058        slave.waitForSuites();
1059     }
1060 
1061     //
1062     // Regular mode
1063     //
1064     else if (m_masterfileName == null) {
1065       suiteRunners = runSuitesLocally();
1066     }
1067 
1068     //
1069     // Master mode
1070     //
1071     else {
1072        SuiteDispatcher dispatcher = new SuiteDispatcher(m_masterfileName);
1073        suiteRunners = dispatcher.dispatch(getConfiguration(),
1074            m_suites, getOutputDirectory(),
1075            getTestListeners());
1076     }
1077 
1078     m_end = System.currentTimeMillis();
1079     runExecutionListeners(false /* finish */);
1080 
1081     if(null != suiteRunners) {
1082       generateReports(suiteRunners);
1083     }
1084 
1085     if(!m_hasTests) {
1086       setStatus(HAS_NO_TEST);
1087       if (TestRunner.getVerbose() > 1) {
1088         System.err.println("[TestNG] No tests found. Nothing was run");
1089         usage();
1090       }
1091     }
1092   }
1093 
p(String string)1094   private void p(String string) {
1095     System.out.println("[TestNG] " + string);
1096   }
1097 
runSuiteAlterationListeners()1098   private void runSuiteAlterationListeners() {
1099     for (List<IAlterSuiteListener> listeners
1100         : Arrays.asList(m_alterSuiteListeners, m_configuration.getAlterSuiteListeners())) {
1101       for (IAlterSuiteListener l : listeners) {
1102         l.alter(m_suites);
1103       }
1104     }
1105   }
1106 
runExecutionListeners(boolean start)1107   private void runExecutionListeners(boolean start) {
1108     for (List<IExecutionListener> listeners
1109         : Arrays.asList(m_executionListeners, m_configuration.getExecutionListeners())) {
1110       for (IExecutionListener l : listeners) {
1111         if (start) l.onExecutionStart();
1112         else l.onExecutionFinish();
1113       }
1114     }
1115   }
1116 
addAlterSuiteListener(IAlterSuiteListener l)1117   public void addAlterSuiteListener(IAlterSuiteListener l) {
1118     m_alterSuiteListeners.add(l);
1119   }
1120 
addExecutionListener(IExecutionListener l)1121   public void addExecutionListener(IExecutionListener l) {
1122     m_executionListeners.add(l);
1123   }
1124 
usage()1125   private static void usage() {
1126     if (m_jCommander == null) {
1127       m_jCommander = new JCommander(new CommandLineArgs());
1128     }
1129     m_jCommander.usage();
1130   }
1131 
generateReports(List<ISuite> suiteRunners)1132   private void generateReports(List<ISuite> suiteRunners) {
1133     for (IReporter reporter : m_reporters) {
1134       try {
1135         long start = System.currentTimeMillis();
1136         reporter.generateReport(m_suites, suiteRunners, m_outputDir);
1137         Utils.log("TestNG", 2, "Time taken by " + reporter + ": "
1138             + (System.currentTimeMillis() - start) + " ms");
1139       }
1140       catch(Exception ex) {
1141         System.err.println("[TestNG] Reporter " + reporter + " failed");
1142         ex.printStackTrace(System.err);
1143       }
1144     }
1145   }
1146 
1147   /**
1148    * This needs to be public for maven2, for now..At least
1149    * until an alternative mechanism is found.
1150    */
runSuitesLocally()1151   public List<ISuite> runSuitesLocally() {
1152     SuiteRunnerMap suiteRunnerMap = new SuiteRunnerMap();
1153     if (m_suites.size() > 0) {
1154       if (m_suites.get(0).getVerbose() >= 2) {
1155         Version.displayBanner();
1156       }
1157 
1158       // First initialize the suite runners to ensure there are no configuration issues.
1159       // Create a map with XmlSuite as key and corresponding SuiteRunner as value
1160       for (XmlSuite xmlSuite : m_suites) {
1161         createSuiteRunners(suiteRunnerMap, xmlSuite);
1162       }
1163 
1164       //
1165       // Run suites
1166       //
1167       if (m_suiteThreadPoolSize == 1 && !m_randomizeSuites) {
1168         // Single threaded and not randomized: run the suites in order
1169         for (XmlSuite xmlSuite : m_suites) {
1170           runSuitesSequentially(xmlSuite, suiteRunnerMap, getVerbose(xmlSuite),
1171               getDefaultSuiteName());
1172         }
1173       } else {
1174         // Multithreaded: generate a dynamic graph that stores the suite hierarchy. This is then
1175         // used to run related suites in specific order. Parent suites are run only
1176         // once all the child suites have completed execution
1177         DynamicGraph<ISuite> suiteGraph = new DynamicGraph<>();
1178         for (XmlSuite xmlSuite : m_suites) {
1179           populateSuiteGraph(suiteGraph, suiteRunnerMap, xmlSuite);
1180         }
1181 
1182         IThreadWorkerFactory<ISuite> factory = new SuiteWorkerFactory(suiteRunnerMap,
1183           0 /* verbose hasn't been set yet */, getDefaultSuiteName());
1184         GraphThreadPoolExecutor<ISuite> pooledExecutor =
1185                 new GraphThreadPoolExecutor<>(suiteGraph, factory, m_suiteThreadPoolSize,
1186                         m_suiteThreadPoolSize, Integer.MAX_VALUE, TimeUnit.MILLISECONDS,
1187                         new LinkedBlockingQueue<Runnable>());
1188 
1189         Utils.log("TestNG", 2, "Starting executor for all suites");
1190         // Run all suites in parallel
1191         pooledExecutor.run();
1192         try {
1193           pooledExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
1194           pooledExecutor.shutdownNow();
1195         }
1196         catch (InterruptedException handled) {
1197           Thread.currentThread().interrupt();
1198           error("Error waiting for concurrent executors to finish " + handled.getMessage());
1199         }
1200       }
1201     }
1202     else {
1203       setStatus(HAS_NO_TEST);
1204       error("No test suite found. Nothing to run");
1205       usage();
1206     }
1207 
1208     //
1209     // Generate the suites report
1210     //
1211     return Lists.newArrayList(suiteRunnerMap.values());
1212   }
1213 
error(String s)1214   private static void error(String s) {
1215     LOGGER.error(s);
1216   }
1217 
1218   /**
1219    * @return the verbose level, checking in order: the verbose level on
1220    * the suite, the verbose level on the TestNG object, or 1.
1221    */
getVerbose(XmlSuite xmlSuite)1222   private int getVerbose(XmlSuite xmlSuite) {
1223     int result = xmlSuite.getVerbose() != null ? xmlSuite.getVerbose()
1224         : (m_verbose != null ? m_verbose : DEFAULT_VERBOSE);
1225     return result;
1226   }
1227 
1228   /**
1229    * Recursively runs suites. Runs the children suites before running the parent
1230    * suite. This is done so that the results for parent suite can reflect the
1231    * combined results of the children suites.
1232    *
1233    * @param xmlSuite XML Suite to be executed
1234    * @param suiteRunnerMap Maps {@code XmlSuite}s to respective {@code ISuite}
1235    * @param verbose verbose level
1236    * @param defaultSuiteName default suite name
1237    */
runSuitesSequentially(XmlSuite xmlSuite, SuiteRunnerMap suiteRunnerMap, int verbose, String defaultSuiteName)1238   private void runSuitesSequentially(XmlSuite xmlSuite,
1239       SuiteRunnerMap suiteRunnerMap, int verbose, String defaultSuiteName) {
1240     for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
1241       runSuitesSequentially(childSuite, suiteRunnerMap, verbose, defaultSuiteName);
1242     }
1243     SuiteRunnerWorker srw = new SuiteRunnerWorker(suiteRunnerMap.get(xmlSuite), suiteRunnerMap,
1244       verbose, defaultSuiteName);
1245     srw.run();
1246   }
1247 
1248   /**
1249    * Populates the dynamic graph with the reverse hierarchy of suites. Edges are
1250    * added pointing from child suite runners to parent suite runners, hence making
1251    * parent suite runners dependent on all the child suite runners
1252    *
1253    * @param suiteGraph dynamic graph representing the reverse hierarchy of SuiteRunners
1254    * @param suiteRunnerMap Map with XMLSuite as key and its respective SuiteRunner as value
1255    * @param xmlSuite XML Suite
1256    */
populateSuiteGraph(DynamicGraph<ISuite> suiteGraph , SuiteRunnerMap suiteRunnerMap, XmlSuite xmlSuite)1257   private void populateSuiteGraph(DynamicGraph<ISuite> suiteGraph /* OUT */,
1258       SuiteRunnerMap suiteRunnerMap, XmlSuite xmlSuite) {
1259     ISuite parentSuiteRunner = suiteRunnerMap.get(xmlSuite);
1260     if (xmlSuite.getChildSuites().isEmpty()) {
1261       suiteGraph.addNode(parentSuiteRunner);
1262     }
1263     else {
1264       for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
1265         suiteGraph.addEdge(parentSuiteRunner, suiteRunnerMap.get(childSuite));
1266         populateSuiteGraph(suiteGraph, suiteRunnerMap, childSuite);
1267       }
1268     }
1269   }
1270 
1271   /**
1272    * Creates the {@code SuiteRunner}s and populates the suite runner map with
1273    * this information
1274    * @param suiteRunnerMap Map with XMLSuite as key and it's respective
1275    *   SuiteRunner as value. This is updated as part of this method call
1276    * @param xmlSuite Xml Suite (and its children) for which {@code SuiteRunner}s are created
1277    */
createSuiteRunners(SuiteRunnerMap suiteRunnerMap , XmlSuite xmlSuite)1278   private void createSuiteRunners(SuiteRunnerMap suiteRunnerMap /* OUT */, XmlSuite xmlSuite) {
1279     if (null != m_isJUnit && ! m_isJUnit.equals(XmlSuite.DEFAULT_JUNIT)) {
1280       xmlSuite.setJUnit(m_isJUnit);
1281     }
1282 
1283     // If the skip flag was invoked on the command line, it
1284     // takes precedence
1285     if (null != m_skipFailedInvocationCounts) {
1286       xmlSuite.setSkipFailedInvocationCounts(m_skipFailedInvocationCounts);
1287     }
1288 
1289     // Override the XmlSuite verbose value with the one from TestNG
1290     if (m_verbose != null) {
1291       xmlSuite.setVerbose(m_verbose);
1292     }
1293 
1294     if (null != m_configFailurePolicy) {
1295       xmlSuite.setConfigFailurePolicy(m_configFailurePolicy);
1296     }
1297 
1298     for (XmlTest t : xmlSuite.getTests()) {
1299       for (Map.Entry<String, Integer> ms : m_methodDescriptors.entrySet()) {
1300         XmlMethodSelector xms = new XmlMethodSelector();
1301         xms.setName(ms.getKey());
1302         xms.setPriority(ms.getValue());
1303         t.getMethodSelectors().add(xms);
1304       }
1305     }
1306 
1307     suiteRunnerMap.put(xmlSuite, createSuiteRunner(xmlSuite));
1308 
1309     for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
1310       createSuiteRunners(suiteRunnerMap, childSuite);
1311     }
1312   }
1313 
1314   /**
1315    * Creates a suite runner and configures its initial state
1316    * @param xmlSuite
1317    * @return returns the newly created suite runner
1318    */
createSuiteRunner(XmlSuite xmlSuite)1319   private SuiteRunner createSuiteRunner(XmlSuite xmlSuite) {
1320     SuiteRunner result = new SuiteRunner(getConfiguration(), xmlSuite,
1321         m_outputDir,
1322         m_testRunnerFactory,
1323         m_useDefaultListeners,
1324         m_methodInterceptors,
1325         m_invokedMethodListeners,
1326         m_testListeners,
1327         m_classListeners);
1328 
1329     for (ISuiteListener isl : m_suiteListeners) {
1330       result.addListener(isl);
1331     }
1332 
1333     for (IReporter r : result.getReporters()) {
1334       addListener(r);
1335     }
1336 
1337     for (IConfigurationListener cl : m_configuration.getConfigurationListeners()) {
1338       result.addConfigurationListener(cl);
1339     }
1340 
1341     return result;
1342   }
1343 
getConfiguration()1344   protected IConfiguration getConfiguration() {
1345     return m_configuration;
1346   }
1347 
1348   /**
1349    * The TestNG entry point for command line execution.
1350    *
1351    * @param argv the TestNG command line parameters.
1352    * @throws FileNotFoundException
1353    */
main(String[] argv)1354   public static void main(String[] argv) {
1355     TestNG testng = privateMain(argv, null);
1356     System.exit(testng.getStatus());
1357   }
1358 
1359   /**
1360    * <B>Note</B>: this method is not part of the public API and is meant for internal usage only.
1361    */
privateMain(String[] argv, ITestListener listener)1362   public static TestNG privateMain(String[] argv, ITestListener listener) {
1363     TestNG result = new TestNG();
1364 
1365     if (null != listener) {
1366       result.addListener(listener);
1367     }
1368 
1369     //
1370     // Parse the arguments
1371     //
1372     try {
1373       CommandLineArgs cla = new CommandLineArgs();
1374       m_jCommander = new JCommander(cla, argv);
1375       validateCommandLineParameters(cla);
1376       result.configure(cla);
1377     }
1378     catch(ParameterException ex) {
1379       exitWithError(ex.getMessage());
1380     }
1381 
1382     //
1383     // Run
1384     //
1385     try {
1386       result.run();
1387     }
1388     catch(TestNGException ex) {
1389       if (TestRunner.getVerbose() > 1) {
1390         ex.printStackTrace(System.out);
1391       }
1392       else {
1393         error(ex.getMessage());
1394       }
1395       result.setStatus(HAS_FAILURE);
1396     }
1397 
1398     return result;
1399   }
1400 
1401   /**
1402    * Configure the TestNG instance based on the command line parameters.
1403    */
configure(CommandLineArgs cla)1404   protected void configure(CommandLineArgs cla) {
1405     if (cla.verbose != null) {
1406       setVerbose(cla.verbose);
1407     }
1408     setOutputDirectory(cla.outputDirectory);
1409 
1410     String testClasses = cla.testClass;
1411     if (null != testClasses) {
1412       String[] strClasses = testClasses.split(",");
1413       List<Class> classes = Lists.newArrayList();
1414       for (String c : strClasses) {
1415         classes.add(ClassHelper.fileToClass(c));
1416       }
1417 
1418       setTestClasses(classes.toArray(new Class[classes.size()]));
1419     }
1420 
1421     setOutputDirectory(cla.outputDirectory);
1422 
1423     if (cla.testNames != null) {
1424       setTestNames(Arrays.asList(cla.testNames.split(",")));
1425     }
1426 
1427 //    List<String> testNgXml = (List<String>) cmdLineArgs.get(CommandLineArgs.SUITE_DEF);
1428 //    if (null != testNgXml) {
1429 //      setTestSuites(testNgXml);
1430 //    }
1431 
1432     // Note: can't use a Boolean field here because we are allowing a boolean
1433     // parameter with an arity of 1 ("-usedefaultlisteners false")
1434     if (cla.useDefaultListeners != null) {
1435       setUseDefaultListeners("true".equalsIgnoreCase(cla.useDefaultListeners));
1436     }
1437 
1438     setGroups(cla.groups);
1439     setExcludedGroups(cla.excludedGroups);
1440     setTestJar(cla.testJar);
1441     setXmlPathInJar(cla.xmlPathInJar);
1442     setJUnit(cla.junit);
1443     setMixed(cla.mixed);
1444     setMaster(cla.master);
1445     setSlave(cla.slave);
1446     setSkipFailedInvocationCounts(cla.skipFailedInvocationCounts);
1447     if (cla.parallelMode != null) {
1448       setParallel(cla.parallelMode);
1449     }
1450     if (cla.configFailurePolicy != null) {
1451       setConfigFailurePolicy(cla.configFailurePolicy);
1452     }
1453     if (cla.threadCount != null) {
1454       setThreadCount(cla.threadCount);
1455     }
1456     if (cla.dataProviderThreadCount != null) {
1457       setDataProviderThreadCount(cla.dataProviderThreadCount);
1458     }
1459     if (cla.suiteName != null) {
1460       setDefaultSuiteName(cla.suiteName);
1461     }
1462     if (cla.testName != null) {
1463       setDefaultTestName(cla.testName);
1464     }
1465     if (cla.listener != null) {
1466       String sep = ";";
1467       if (cla.listener.contains(",")) {
1468         sep = ",";
1469       }
1470       String[] strs = Utils.split(cla.listener, sep);
1471       List<Class> classes = Lists.newArrayList();
1472 
1473       for (String cls : strs) {
1474         classes.add(ClassHelper.fileToClass(cls));
1475       }
1476 
1477       setListenerClasses(classes);
1478     }
1479 
1480     if (null != cla.methodSelectors) {
1481       String[] strs = Utils.split(cla.methodSelectors, ",");
1482       for (String cls : strs) {
1483         String[] sel = Utils.split(cls, ":");
1484         try {
1485           if (sel.length == 2) {
1486             addMethodSelector(sel[0], Integer.parseInt(sel[1]));
1487           } else {
1488             error("Method selector value was not in the format org.example.Selector:4");
1489           }
1490         }
1491         catch (NumberFormatException nfe) {
1492           error("Method selector value was not in the format org.example.Selector:4");
1493         }
1494       }
1495     }
1496 
1497     if (cla.objectFactory != null) {
1498       setObjectFactory(ClassHelper.fileToClass(cla.objectFactory));
1499     }
1500     if (cla.testRunnerFactory != null) {
1501       setTestRunnerFactoryClass(
1502           ClassHelper.fileToClass(cla.testRunnerFactory));
1503     }
1504 
1505     if (cla.reporter != null) {
1506       ReporterConfig reporterConfig = ReporterConfig.deserialize(cla.reporter);
1507       addReporter(reporterConfig);
1508     }
1509 
1510     if (cla.commandLineMethods.size() > 0) {
1511       m_commandLineMethods = cla.commandLineMethods;
1512     }
1513 
1514     if (cla.suiteFiles != null) {
1515       setTestSuites(cla.suiteFiles);
1516     }
1517 
1518     setSuiteThreadPoolSize(cla.suiteThreadPoolSize);
1519     setRandomizeSuites(cla.randomizeSuites);
1520   }
1521 
setSuiteThreadPoolSize(Integer suiteThreadPoolSize)1522   public void setSuiteThreadPoolSize(Integer suiteThreadPoolSize) {
1523     m_suiteThreadPoolSize = suiteThreadPoolSize;
1524   }
1525 
getSuiteThreadPoolSize()1526   public Integer getSuiteThreadPoolSize() {
1527     return m_suiteThreadPoolSize;
1528   }
1529 
setRandomizeSuites(boolean randomizeSuites)1530    public void setRandomizeSuites(boolean randomizeSuites) {
1531      m_randomizeSuites = randomizeSuites;
1532    }
1533 
1534   /**
1535    * This method is invoked by Maven's Surefire, only remove it once
1536    * Surefire has been modified to no longer call it.
1537    */
setSourcePath(String path)1538   public void setSourcePath(String path) {
1539     // nop
1540   }
1541 
1542   /**
1543    * This method is invoked by Maven's Surefire to configure the runner,
1544    * do not remove unless you know for sure that Surefire has been updated
1545    * to use the new configure(CommandLineArgs) method.
1546    *
1547    * @deprecated use new configure(CommandLineArgs) method
1548    */
1549   @SuppressWarnings({"unchecked"})
1550   @Deprecated
configure(Map cmdLineArgs)1551   public void configure(Map cmdLineArgs) {
1552     CommandLineArgs result = new CommandLineArgs();
1553 
1554     Integer verbose = (Integer) cmdLineArgs.get(CommandLineArgs.LOG);
1555     if (null != verbose) {
1556       result.verbose = verbose;
1557     }
1558     result.outputDirectory = (String) cmdLineArgs.get(CommandLineArgs.OUTPUT_DIRECTORY);
1559 
1560     String testClasses = (String) cmdLineArgs.get(CommandLineArgs.TEST_CLASS);
1561     if (null != testClasses) {
1562       result.testClass = testClasses;
1563     }
1564 
1565     String testNames = (String) cmdLineArgs.get(CommandLineArgs.TEST_NAMES);
1566     if (testNames != null) {
1567       result.testNames = testNames;
1568     }
1569 
1570     String useDefaultListeners = (String) cmdLineArgs.get(CommandLineArgs.USE_DEFAULT_LISTENERS);
1571     if (null != useDefaultListeners) {
1572       result.useDefaultListeners = useDefaultListeners;
1573     }
1574 
1575     result.groups = (String) cmdLineArgs.get(CommandLineArgs.GROUPS);
1576     result.excludedGroups = (String) cmdLineArgs.get(CommandLineArgs.EXCLUDED_GROUPS);
1577     result.testJar = (String) cmdLineArgs.get(CommandLineArgs.TEST_JAR);
1578     result.xmlPathInJar = (String) cmdLineArgs.get(CommandLineArgs.XML_PATH_IN_JAR);
1579     result.junit = (Boolean) cmdLineArgs.get(CommandLineArgs.JUNIT);
1580     result.mixed = (Boolean) cmdLineArgs.get(CommandLineArgs.MIXED);
1581     result.master = (String) cmdLineArgs.get(CommandLineArgs.MASTER);
1582     result.slave = (String) cmdLineArgs.get(CommandLineArgs.SLAVE);
1583     result.skipFailedInvocationCounts = (Boolean) cmdLineArgs.get(
1584         CommandLineArgs.SKIP_FAILED_INVOCATION_COUNTS);
1585     String parallelMode = (String) cmdLineArgs.get(CommandLineArgs.PARALLEL);
1586     if (parallelMode != null) {
1587       result.parallelMode = XmlSuite.ParallelMode.getValidParallel(parallelMode);
1588     }
1589 
1590     String threadCount = (String) cmdLineArgs.get(CommandLineArgs.THREAD_COUNT);
1591     if (threadCount != null) {
1592       result.threadCount = Integer.parseInt(threadCount);
1593     }
1594 
1595     // Not supported by Surefire yet
1596     Integer dptc = (Integer) cmdLineArgs.get(CommandLineArgs.DATA_PROVIDER_THREAD_COUNT);
1597     if (dptc != null) {
1598       result.dataProviderThreadCount = dptc;
1599     }
1600     String defaultSuiteName = (String) cmdLineArgs.get(CommandLineArgs.SUITE_NAME);
1601     if (defaultSuiteName != null) {
1602       result.suiteName = defaultSuiteName;
1603     }
1604 
1605     String defaultTestName = (String) cmdLineArgs.get(CommandLineArgs.TEST_NAME);
1606     if (defaultTestName != null) {
1607       result.testName = defaultTestName;
1608     }
1609 
1610     Object listeners = cmdLineArgs.get(CommandLineArgs.LISTENER);
1611     if (listeners instanceof List) {
1612       result.listener = Utils.join((List<?>) listeners, ",");
1613     } else {
1614       result.listener = (String) listeners;
1615     }
1616 
1617     String ms = (String) cmdLineArgs.get(CommandLineArgs.METHOD_SELECTORS);
1618     if (null != ms) {
1619       result.methodSelectors = ms;
1620     }
1621 
1622     String objectFactory = (String) cmdLineArgs.get(CommandLineArgs.OBJECT_FACTORY);
1623     if(null != objectFactory) {
1624       result.objectFactory = objectFactory;
1625     }
1626 
1627     String runnerFactory = (String) cmdLineArgs.get(CommandLineArgs.TEST_RUNNER_FACTORY);
1628     if (null != runnerFactory) {
1629       result.testRunnerFactory = runnerFactory;
1630     }
1631 
1632     String reporterConfigs = (String) cmdLineArgs.get(CommandLineArgs.REPORTER);
1633     if (reporterConfigs != null) {
1634       result.reporter = reporterConfigs;
1635     }
1636 
1637     String failurePolicy = (String)cmdLineArgs.get(CommandLineArgs.CONFIG_FAILURE_POLICY);
1638     if (failurePolicy != null) {
1639       result.configFailurePolicy = failurePolicy;
1640     }
1641 
1642     Object  suiteThreadPoolSize = cmdLineArgs.get(CommandLineArgs.SUITE_THREAD_POOL_SIZE);
1643     if (null != suiteThreadPoolSize) {
1644         if (suiteThreadPoolSize instanceof String){
1645             result.suiteThreadPoolSize=Integer.parseInt((String) suiteThreadPoolSize);
1646         }
1647         if (suiteThreadPoolSize instanceof Integer){
1648             result.suiteThreadPoolSize=(Integer) suiteThreadPoolSize;
1649         }
1650     }
1651 
1652     configure(result);
1653   }
1654 
1655   /**
1656    * Only run the specified tests from the suite.
1657    */
setTestNames(List<String> testNames)1658   public void setTestNames(List<String> testNames) {
1659     m_testNames = testNames;
1660   }
1661 
setSkipFailedInvocationCounts(Boolean skip)1662   public void setSkipFailedInvocationCounts(Boolean skip) {
1663     m_skipFailedInvocationCounts = skip;
1664   }
1665 
addReporter(ReporterConfig reporterConfig)1666   private void addReporter(ReporterConfig reporterConfig) {
1667     Object instance = reporterConfig.newReporterInstance();
1668     if (instance != null) {
1669       addListener(instance);
1670     } else {
1671       LOGGER.warn("Could not find reporte class : " + reporterConfig.getClassName());
1672     }
1673   }
1674 
1675   /**
1676    * Specify if this run should be in Master-Slave mode as Master
1677    *
1678    * @param fileName remote.properties path
1679    */
setMaster(String fileName)1680   public void setMaster(String fileName) {
1681      m_masterfileName = fileName;
1682   }
1683 
1684   /**
1685    * Specify if this run should be in Master-Slave mode as slave
1686    *
1687    * @param fileName remote.properties path
1688    */
setSlave(String fileName)1689   public void setSlave(String fileName) {
1690      m_slavefileName = fileName;
1691   }
1692 
1693   /**
1694    * Specify if this run should be made in JUnit mode
1695    *
1696    * @param isJUnit
1697    */
setJUnit(Boolean isJUnit)1698   public void setJUnit(Boolean isJUnit) {
1699     m_isJUnit = isJUnit;
1700   }
1701 
1702   /**
1703    * Specify if this run should be made in mixed mode
1704    */
setMixed(Boolean isMixed)1705   public void setMixed(Boolean isMixed) {
1706       if(isMixed==null){
1707           return;
1708       }
1709     m_isMixed = isMixed;
1710   }
1711 
1712   /**
1713    * @deprecated The TestNG version is now established at load time. This
1714    * method is not required anymore and is now a no-op.
1715    */
1716   @Deprecated
setTestNGVersion()1717   public static void setTestNGVersion() {
1718     LOGGER.info("setTestNGVersion has been deprecated.");
1719   }
1720 
1721   /**
1722    * Returns true if this is the JDK 1.4 JAR version of TestNG, false otherwise.
1723    *
1724    * @return true if this is the JDK 1.4 JAR version of TestNG, false otherwise.
1725    */
1726   @Deprecated
isJdk14()1727   public static boolean isJdk14() {
1728     return false;
1729   }
1730 
1731   /**
1732    * Double check that the command line parameters are valid.
1733    */
validateCommandLineParameters(CommandLineArgs args)1734   protected static void validateCommandLineParameters(CommandLineArgs args) {
1735     String testClasses = args.testClass;
1736     List<String> testNgXml = args.suiteFiles;
1737     String testJar = args.testJar;
1738     String slave = args.slave;
1739     List<String> methods = args.commandLineMethods;
1740 
1741     if (testClasses == null && slave == null && testJar == null
1742         && (testNgXml == null || testNgXml.isEmpty())
1743         && (methods == null || methods.isEmpty())) {
1744       throw new ParameterException("You need to specify at least one testng.xml, one class"
1745           + " or one method");
1746     }
1747 
1748     String groups = args.groups;
1749     String excludedGroups = args.excludedGroups;
1750 
1751     if (testJar == null &&
1752         (null != groups || null != excludedGroups) && testClasses == null
1753         && (testNgXml == null || testNgXml.isEmpty())) {
1754       throw new ParameterException("Groups option should be used with testclass option");
1755     }
1756 
1757     if (args.slave != null && args.master != null) {
1758      throw new ParameterException(CommandLineArgs.SLAVE + " can't be combined with "
1759          + CommandLineArgs.MASTER);
1760     }
1761 
1762     Boolean junit = args.junit;
1763     Boolean mixed = args.mixed;
1764     if (junit && mixed) {
1765      throw new ParameterException(CommandLineArgs.MIXED + " can't be combined with "
1766          + CommandLineArgs.JUNIT);
1767     }
1768   }
1769 
1770   /**
1771    * @return true if at least one test failed.
1772    */
hasFailure()1773   public boolean hasFailure() {
1774     return (getStatus() & HAS_FAILURE) == HAS_FAILURE;
1775   }
1776 
1777   /**
1778    * @return true if at least one test failed within success percentage.
1779    */
hasFailureWithinSuccessPercentage()1780   public boolean hasFailureWithinSuccessPercentage() {
1781     return (getStatus() & HAS_FSP) == HAS_FSP;
1782   }
1783 
1784   /**
1785    * @return true if at least one test was skipped.
1786    */
hasSkip()1787   public boolean hasSkip() {
1788     return (getStatus() & HAS_SKIPPED) == HAS_SKIPPED;
1789   }
1790 
exitWithError(String msg)1791   static void exitWithError(String msg) {
1792     System.err.println(msg);
1793     usage();
1794     System.exit(1);
1795   }
1796 
getOutputDirectory()1797   public String getOutputDirectory() {
1798     return m_outputDir;
1799   }
1800 
getAnnotationTransformer()1801   public IAnnotationTransformer getAnnotationTransformer() {
1802     return m_annotationTransformer;
1803   }
1804 
setAnnotationTransformer(IAnnotationTransformer t)1805   public void setAnnotationTransformer(IAnnotationTransformer t) {
1806 	// compare by reference!
1807     if (m_annotationTransformer != m_defaultAnnoProcessor && m_annotationTransformer != t) {
1808     	LOGGER.warn("AnnotationTransformer already set");
1809     }
1810     m_annotationTransformer = t;
1811   }
1812 
1813   /**
1814    * @return the defaultSuiteName
1815    */
getDefaultSuiteName()1816   public String getDefaultSuiteName() {
1817     return m_defaultSuiteName;
1818   }
1819 
1820   /**
1821    * @param defaultSuiteName the defaultSuiteName to set
1822    */
setDefaultSuiteName(String defaultSuiteName)1823   public void setDefaultSuiteName(String defaultSuiteName) {
1824     m_defaultSuiteName = defaultSuiteName;
1825   }
1826 
1827   /**
1828    * @return the defaultTestName
1829    */
getDefaultTestName()1830   public String getDefaultTestName() {
1831     return m_defaultTestName;
1832   }
1833 
1834   /**
1835    * @param defaultTestName the defaultTestName to set
1836    */
setDefaultTestName(String defaultTestName)1837   public void setDefaultTestName(String defaultTestName) {
1838     m_defaultTestName = defaultTestName;
1839   }
1840 
1841   /**
1842    * Sets the policy for whether or not to ever invoke a configuration method again after
1843    * it has failed once. Possible values are defined in {@link XmlSuite}.  The default
1844    * value is {@link XmlSuite#SKIP}.
1845    * @param failurePolicy the configuration failure policy
1846    */
setConfigFailurePolicy(String failurePolicy)1847   public void setConfigFailurePolicy(String failurePolicy) {
1848     m_configFailurePolicy = failurePolicy;
1849   }
1850 
1851   /**
1852    * Returns the configuration failure policy.
1853    * @return config failure policy
1854    */
getConfigFailurePolicy()1855   public String getConfigFailurePolicy() {
1856     return m_configFailurePolicy;
1857   }
1858 
1859   // DEPRECATED: to be removed after a major version change
1860   /**
1861    * @deprecated since 5.1
1862    */
1863   @Deprecated
getDefault()1864   public static TestNG getDefault() {
1865     return m_instance;
1866   }
1867 
1868   /**
1869    * @deprecated since 5.1
1870    */
1871   @Deprecated
setHasFailure(boolean hasFailure)1872   public void setHasFailure(boolean hasFailure) {
1873     m_status |= HAS_FAILURE;
1874   }
1875 
1876   /**
1877    * @deprecated since 5.1
1878    */
1879   @Deprecated
setHasFailureWithinSuccessPercentage(boolean hasFailureWithinSuccessPercentage)1880   public void setHasFailureWithinSuccessPercentage(boolean hasFailureWithinSuccessPercentage) {
1881     m_status |= HAS_FSP;
1882   }
1883 
1884   /**
1885    * @deprecated since 5.1
1886    */
1887   @Deprecated
setHasSkip(boolean hasSkip)1888   public void setHasSkip(boolean hasSkip) {
1889     m_status |= HAS_SKIPPED;
1890   }
1891 
1892   public static class ExitCodeListener implements IResultListener2 {
1893     private TestNG m_mainRunner;
1894 
ExitCodeListener()1895     public ExitCodeListener() {
1896       m_mainRunner = TestNG.m_instance;
1897     }
1898 
ExitCodeListener(TestNG runner)1899     public ExitCodeListener(TestNG runner) {
1900       m_mainRunner = runner;
1901     }
1902 
1903     @Override
beforeConfiguration(ITestResult tr)1904     public void beforeConfiguration(ITestResult tr) {
1905     }
1906 
1907     @Override
onTestFailure(ITestResult result)1908     public void onTestFailure(ITestResult result) {
1909       setHasRunTests();
1910       m_mainRunner.setStatus(HAS_FAILURE);
1911     }
1912 
1913     @Override
onTestSkipped(ITestResult result)1914     public void onTestSkipped(ITestResult result) {
1915       setHasRunTests();
1916       if ((m_mainRunner.getStatus() & HAS_FAILURE) != 0) {
1917         m_mainRunner.setStatus(HAS_SKIPPED);
1918       }
1919     }
1920 
1921     @Override
onTestFailedButWithinSuccessPercentage(ITestResult result)1922     public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
1923       setHasRunTests();
1924       m_mainRunner.setStatus(HAS_FSP);
1925     }
1926 
1927     @Override
onTestSuccess(ITestResult result)1928     public void onTestSuccess(ITestResult result) {
1929       setHasRunTests();
1930     }
1931 
1932     @Override
onStart(ITestContext context)1933     public void onStart(ITestContext context) {
1934       setHasRunTests();
1935     }
1936 
1937     @Override
onFinish(ITestContext context)1938     public void onFinish(ITestContext context) {
1939     }
1940 
1941     @Override
onTestStart(ITestResult result)1942     public void onTestStart(ITestResult result) {
1943       setHasRunTests();
1944     }
1945 
setHasRunTests()1946     private void setHasRunTests() {
1947       m_mainRunner.m_hasTests= true;
1948     }
1949 
1950     /**
1951      * @see org.testng.IConfigurationListener#onConfigurationFailure(org.testng.ITestResult)
1952      */
1953     @Override
onConfigurationFailure(ITestResult itr)1954     public void onConfigurationFailure(ITestResult itr) {
1955       m_mainRunner.setStatus(HAS_FAILURE);
1956     }
1957 
1958     /**
1959      * @see org.testng.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult)
1960      */
1961     @Override
onConfigurationSkip(ITestResult itr)1962     public void onConfigurationSkip(ITestResult itr) {
1963       m_mainRunner.setStatus(HAS_SKIPPED);
1964     }
1965 
1966     /**
1967      * @see org.testng.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult)
1968      */
1969     @Override
onConfigurationSuccess(ITestResult itr)1970     public void onConfigurationSuccess(ITestResult itr) {
1971     }
1972   }
1973 
setConfigurable(IConfigurable c)1974   private void setConfigurable(IConfigurable c) {
1975 	// compare by reference!
1976     if (m_configurable != null && m_configurable != c) {
1977     	LOGGER.warn("Configurable already set");
1978 	}
1979     m_configurable = c;
1980   }
1981 
setHookable(IHookable h)1982   private void setHookable(IHookable h) {
1983 	// compare by reference!
1984     if (m_hookable != null && m_hookable != h) {
1985     	LOGGER.warn("Hookable already set");
1986     }
1987     m_hookable = h;
1988   }
1989 
setMethodInterceptor(IMethodInterceptor methodInterceptor)1990   public void setMethodInterceptor(IMethodInterceptor methodInterceptor) {
1991     m_methodInterceptors.add(methodInterceptor);
1992   }
1993 
setDataProviderThreadCount(int count)1994   public void setDataProviderThreadCount(int count) {
1995     m_dataProviderThreadCount = count;
1996   }
1997 
1998   /** Add a class loader to the searchable loaders. */
addClassLoader(final ClassLoader loader)1999   public void addClassLoader(final ClassLoader loader) {
2000     if (loader != null) {
2001       ClassHelper.addClassLoader(loader);
2002     }
2003   }
2004 
setPreserveOrder(boolean b)2005   public void setPreserveOrder(boolean b) {
2006     m_preserveOrder = b;
2007   }
2008 
getStart()2009   protected long getStart() {
2010     return m_start;
2011   }
2012 
getEnd()2013   protected long getEnd() {
2014     return m_end;
2015   }
2016 
setGroupByInstances(boolean b)2017   public void setGroupByInstances(boolean b) {
2018     m_groupByInstances = b;
2019   }
2020 
2021   /////
2022   // ServiceLoader testing
2023   //
2024 
2025   private URLClassLoader m_serviceLoaderClassLoader;
2026   private List<ITestNGListener> m_serviceLoaderListeners = Lists.newArrayList();
2027 
2028   /*
2029    * Used to test ServiceClassLoader
2030    */
setServiceLoaderClassLoader(URLClassLoader ucl)2031   public void setServiceLoaderClassLoader(URLClassLoader ucl) {
2032     m_serviceLoaderClassLoader = ucl;
2033   }
2034 
2035   /*
2036    * Used to test ServiceClassLoader
2037    */
addServiceLoaderListener(ITestNGListener l)2038   private void addServiceLoaderListener(ITestNGListener l) {
2039     m_serviceLoaderListeners.add(l);
2040   }
2041 
2042   /*
2043    * Used to test ServiceClassLoader
2044    */
getServiceLoaderListeners()2045   public List<ITestNGListener> getServiceLoaderListeners() {
2046     return m_serviceLoaderListeners;
2047   }
2048 
2049   //
2050   // ServiceLoader testing
2051   /////
2052 }
2053