• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.testng;
2 
3 import java.lang.annotation.Annotation;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.Comparator;
9 import java.util.Date;
10 import java.util.EnumSet;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.concurrent.LinkedBlockingQueue;
15 import java.util.concurrent.TimeUnit;
16 
17 import org.testng.annotations.Guice;
18 import org.testng.annotations.IListenersAnnotation;
19 import org.testng.collections.ListMultiMap;
20 import org.testng.collections.Lists;
21 import org.testng.collections.Maps;
22 import org.testng.collections.Sets;
23 import org.testng.internal.Attributes;
24 import org.testng.internal.ClassHelper;
25 import org.testng.internal.ClassImpl;
26 import org.testng.internal.ClassInfoMap;
27 import org.testng.internal.ConfigurationGroupMethods;
28 import org.testng.internal.Constants;
29 import org.testng.internal.DynamicGraph;
30 import org.testng.internal.DynamicGraph.Status;
31 import org.testng.internal.IConfiguration;
32 import org.testng.internal.IInvoker;
33 import org.testng.internal.ITestResultNotifier;
34 import org.testng.internal.InvokedMethod;
35 import org.testng.internal.Invoker;
36 import org.testng.internal.MethodGroupsHelper;
37 import org.testng.internal.MethodHelper;
38 import org.testng.internal.MethodInstance;
39 import org.testng.internal.ResultMap;
40 import org.testng.internal.RunInfo;
41 import org.testng.internal.TestMethodWorker;
42 import org.testng.internal.TestNGClassFinder;
43 import org.testng.internal.TestNGMethodFinder;
44 import org.testng.internal.Utils;
45 import org.testng.internal.XmlMethodSelector;
46 import org.testng.internal.annotations.AnnotationHelper;
47 import org.testng.internal.annotations.IAnnotationFinder;
48 import org.testng.internal.annotations.IListeners;
49 import org.testng.internal.thread.graph.GraphThreadPoolExecutor;
50 import org.testng.internal.thread.graph.IThreadWorkerFactory;
51 import org.testng.internal.thread.graph.IWorker;
52 import org.testng.junit.IJUnitTestRunner;
53 import org.testng.xml.XmlClass;
54 import org.testng.xml.XmlInclude;
55 import org.testng.xml.XmlPackage;
56 import org.testng.xml.XmlSuite;
57 import org.testng.xml.XmlTest;
58 
59 import com.google.inject.Injector;
60 import com.google.inject.Module;
61 
62 /**
63  * This class takes care of running one Test.
64  *
65  * @author Cedric Beust, Apr 26, 2004
66  */
67 public class TestRunner
68     implements ITestContext, ITestResultNotifier, IThreadWorkerFactory<ITestNGMethod>
69 {
70   /* generated */
71   private static final long serialVersionUID = 4247820024988306670L;
72   private ISuite m_suite;
73   private XmlTest m_xmlTest;
74   private String m_testName;
75 
76   transient private List<XmlClass> m_testClassesFromXml= null;
77   transient private List<XmlPackage> m_packageNamesFromXml= null;
78 
79   transient private IInvoker m_invoker= null;
80   transient private IAnnotationFinder m_annotationFinder= null;
81 
82   /** ITestListeners support. */
83   transient private List<ITestListener> m_testListeners = Lists.newArrayList();
84   transient private Set<IConfigurationListener> m_configurationListeners = Sets.newHashSet();
85 
86   transient private IConfigurationListener m_confListener= new ConfigurationListener();
87   transient private boolean m_skipFailedInvocationCounts;
88 
89   transient private Collection<IInvokedMethodListener> m_invokedMethodListeners = Lists.newArrayList();
90   transient private List<IClassListener> m_classListeners = Lists.newArrayList();
91 
92   /**
93    * All the test methods we found, associated with their respective classes.
94    * Note that these test methods might belong to different classes.
95    * We pick which ones to run at runtime.
96    */
97   private ITestNGMethod[] m_allTestMethods = new ITestNGMethod[0];
98 
99   // Information about this test run
100 
101   private Date m_startDate = null;
102   private Date m_endDate = null;
103 
104   /** A map to keep track of Class <-> IClass. */
105   transient private Map<Class<?>, ITestClass> m_classMap = Maps.newLinkedHashMap();
106 
107   /** Where the reports will be created. */
108   private String m_outputDirectory= Constants.getDefaultValueFor(Constants.PROP_OUTPUT_DIR);
109 
110   // The XML method selector (groups/methods included/excluded in XML)
111   private XmlMethodSelector m_xmlMethodSelector = new XmlMethodSelector();
112 
113   private static int m_verbose = 1;
114 
115   //
116   // These next fields contain all the configuration methods found on this class.
117   // At initialization time, they just contain all the various @Configuration methods
118   // found in all the classes we are going to run.  When comes the time to run them,
119   // only a subset of them are run:  those that are enabled and belong on the same class as
120   // (or a parent of) the test class.
121   //
122   /** */
123   private ITestNGMethod[] m_beforeSuiteMethods = {};
124   private ITestNGMethod[] m_afterSuiteMethods = {};
125   private ITestNGMethod[] m_beforeXmlTestMethods = {};
126   private ITestNGMethod[] m_afterXmlTestMethods = {};
127   private List<ITestNGMethod> m_excludedMethods = Lists.newArrayList();
128   private ConfigurationGroupMethods m_groupMethods = null;
129 
130   // Meta groups
131   private Map<String, List<String>> m_metaGroups = Maps.newHashMap();
132 
133   // All the tests that were run along with their result
134   private IResultMap m_passedTests = new ResultMap();
135   private IResultMap m_failedTests = new ResultMap();
136   private IResultMap m_failedButWithinSuccessPercentageTests = new ResultMap();
137   private IResultMap m_skippedTests = new ResultMap();
138 
139   private RunInfo m_runInfo= new RunInfo();
140 
141   // The host where this test was run, or null if run locally
142   private String m_host;
143 
144   // Defined dynamically depending on <test preserve-order="true/false">
145   transient private List<IMethodInterceptor> m_methodInterceptors;
146 
147   private transient ClassMethodMap m_classMethodMap;
148   private transient TestNGClassFinder m_testClassFinder;
149   private transient IConfiguration m_configuration;
150   private IMethodInterceptor builtinInterceptor;
151 
TestRunner(IConfiguration configuration, ISuite suite, XmlTest test, String outputDirectory, IAnnotationFinder finder, boolean skipFailedInvocationCounts, Collection<IInvokedMethodListener> invokedMethodListeners, List<IClassListener> classListeners)152   protected TestRunner(IConfiguration configuration,
153                     ISuite suite,
154                     XmlTest test,
155                     String outputDirectory,
156                     IAnnotationFinder finder,
157                     boolean skipFailedInvocationCounts,
158                     Collection<IInvokedMethodListener> invokedMethodListeners,
159                     List<IClassListener> classListeners)
160   {
161     init(configuration, suite, test, outputDirectory, finder, skipFailedInvocationCounts,
162         invokedMethodListeners, classListeners);
163   }
164 
TestRunner(IConfiguration configuration, ISuite suite, XmlTest test, boolean skipFailedInvocationCounts, Collection<IInvokedMethodListener> invokedMethodListeners, List<IClassListener> classListeners)165   public TestRunner(IConfiguration configuration, ISuite suite, XmlTest test,
166       boolean skipFailedInvocationCounts,
167       Collection<IInvokedMethodListener> invokedMethodListeners,
168       List<IClassListener> classListeners) {
169     init(configuration, suite, test, suite.getOutputDirectory(),
170         suite.getAnnotationFinder(),
171         skipFailedInvocationCounts, invokedMethodListeners, classListeners);
172   }
173 
init(IConfiguration configuration, ISuite suite, XmlTest test, String outputDirectory, IAnnotationFinder annotationFinder, boolean skipFailedInvocationCounts, Collection<IInvokedMethodListener> invokedMethodListeners, List<IClassListener> classListeners)174   private void init(IConfiguration configuration,
175                     ISuite suite,
176                     XmlTest test,
177                     String outputDirectory,
178                     IAnnotationFinder annotationFinder,
179                     boolean skipFailedInvocationCounts,
180                     Collection<IInvokedMethodListener> invokedMethodListeners,
181                     List<IClassListener> classListeners)
182   {
183     m_configuration = configuration;
184     m_xmlTest= test;
185     m_suite = suite;
186     m_testName = test.getName();
187     m_host = suite.getHost();
188     m_testClassesFromXml= test.getXmlClasses();
189     m_skipFailedInvocationCounts = skipFailedInvocationCounts;
190     setVerbose(test.getVerbose());
191 
192 
193     boolean preserveOrder = "true".equalsIgnoreCase(test.getPreserveOrder());
194     m_methodInterceptors = new ArrayList<IMethodInterceptor>();
195     builtinInterceptor = preserveOrder ? new PreserveOrderMethodInterceptor() : new InstanceOrderingMethodInterceptor();
196 
197     m_packageNamesFromXml= test.getXmlPackages();
198     if(null != m_packageNamesFromXml) {
199       for(XmlPackage xp: m_packageNamesFromXml) {
200         m_testClassesFromXml.addAll(xp.getXmlClasses());
201       }
202     }
203 
204     m_annotationFinder= annotationFinder;
205     m_invokedMethodListeners = invokedMethodListeners;
206     m_classListeners = classListeners;
207     m_invoker = new Invoker(m_configuration, this, this, m_suite.getSuiteState(),
208         m_skipFailedInvocationCounts, invokedMethodListeners, classListeners);
209 
210     if (suite.getParallel() != null) {
211       log(3, "Running the tests in '" + test.getName() + "' with parallel mode:" + suite.getParallel());
212     }
213 
214     setOutputDirectory(outputDirectory);
215 
216     // Finish our initialization
217     init();
218   }
219 
getInvoker()220   public IInvoker getInvoker() {
221     return m_invoker;
222   }
223 
getBeforeSuiteMethods()224   public ITestNGMethod[] getBeforeSuiteMethods() {
225     return m_beforeSuiteMethods;
226   }
227 
getAfterSuiteMethods()228   public ITestNGMethod[] getAfterSuiteMethods() {
229     return m_afterSuiteMethods;
230   }
231 
getBeforeTestConfigurationMethods()232   public ITestNGMethod[] getBeforeTestConfigurationMethods() {
233     return m_beforeXmlTestMethods;
234   }
235 
getAfterTestConfigurationMethods()236   public ITestNGMethod[] getAfterTestConfigurationMethods() {
237     return m_afterXmlTestMethods;
238   }
239 
init()240   private void init() {
241     initMetaGroups(m_xmlTest);
242     initRunInfo(m_xmlTest);
243 
244     // Init methods and class map
245     // JUnit behavior is different and doesn't need this initialization step
246     if(!m_xmlTest.isJUnit()) {
247       initMethods();
248     }
249 
250     initListeners();
251     addConfigurationListener(m_confListener);
252   }
253 
254   private static class ListenerHolder {
255     private List<Class<? extends ITestNGListener>> listenerClasses;
256     private Class<? extends ITestNGListenerFactory> listenerFactoryClass;
257   }
258 
259   /**
260    * @return all the @Listeners annotations found in the current class and its
261    * superclasses.
262    */
findAllListeners(Class<?> cls)263   private ListenerHolder findAllListeners(Class<?> cls) {
264     ListenerHolder result = new ListenerHolder();
265     result.listenerClasses = Lists.newArrayList();
266 
267     do {
268       IListenersAnnotation l = m_annotationFinder.findAnnotation(cls, IListenersAnnotation.class);
269       if (l != null) {
270         Class<? extends ITestNGListener>[] classes = l.getValue();
271         for (Class<? extends ITestNGListener> c : classes) {
272           result.listenerClasses.add(c);
273 
274           if (ITestNGListenerFactory.class.isAssignableFrom(c)) {
275             if (result.listenerFactoryClass == null) {
276               result.listenerFactoryClass = (Class<? extends ITestNGListenerFactory>) c;
277             }
278             else {
279               throw new TestNGException("Found more than one class implementing" +
280                   "ITestNGListenerFactory:" + c + " and " + result.listenerFactoryClass);
281             }
282           }
283         }
284       }
285       cls = cls.getSuperclass();
286     } while (cls != Object.class);
287 
288     return result;
289   }
290 
initListeners()291   private void initListeners() {
292     //
293     // Find all the listener factories and collect all the listeners requested in a
294     // @Listeners annotation.
295     //
296     Set<Class<? extends ITestNGListener>> listenerClasses = Sets.newHashSet();
297     Class<? extends ITestNGListenerFactory> listenerFactoryClass = null;
298 
299     for (IClass cls : getTestClasses()) {
300       Class<? extends ITestNGListenerFactory> realClass = cls.getRealClass();
301       ListenerHolder listenerHolder = findAllListeners(realClass);
302       if (listenerFactoryClass == null) {
303         listenerFactoryClass = listenerHolder.listenerFactoryClass;
304       }
305       listenerClasses.addAll(listenerHolder.listenerClasses);
306     }
307 
308     //
309     // Now we have all the listeners collected from @Listeners and at most one
310     // listener factory collected from a class implementing ITestNGListenerFactory.
311     // Instantiate all the requested listeners.
312     //
313     ITestNGListenerFactory listenerFactory = null;
314 
315     // If we found a test listener factory, instantiate it.
316     try {
317       if (m_testClassFinder != null) {
318         IClass ic = m_testClassFinder.getIClass(listenerFactoryClass);
319         if (ic != null) {
320           listenerFactory = (ITestNGListenerFactory) ic.getInstances(false)[0];
321         }
322       }
323       if (listenerFactory == null) {
324         listenerFactory = listenerFactoryClass != null ? listenerFactoryClass.newInstance() : null;
325       }
326     }
327     catch(Exception ex) {
328       throw new TestNGException("Couldn't instantiate the ITestNGListenerFactory: "
329           + ex);
330     }
331 
332     // Instantiate all the listeners
333     for (Class<? extends ITestNGListener> c : listenerClasses) {
334       Object listener = listenerFactory != null ? listenerFactory.createListener(c) : null;
335       if (listener == null) {
336         listener = ClassHelper.newInstance(c);
337       }
338 
339       if (listener instanceof IMethodInterceptor) {
340         m_methodInterceptors.add((IMethodInterceptor) listener);
341       }
342       if (listener instanceof ISuiteListener) {
343         m_suite.addListener((ISuiteListener) listener);
344       }
345       if (listener instanceof IInvokedMethodListener) {
346         m_suite.addListener((ITestNGListener) listener);
347       }
348       if (listener instanceof ITestListener) {
349         // At this point, the field m_testListeners has already been used in the creation
350         addTestListener((ITestListener) listener);
351       }
352       if (listener instanceof IClassListener) {
353         m_classListeners.add((IClassListener) listener);
354       }
355       if (listener instanceof IConfigurationListener) {
356         addConfigurationListener((IConfigurationListener) listener);
357       }
358       if (listener instanceof IReporter) {
359         m_suite.addListener((ITestNGListener) listener);
360       }
361       if (listener instanceof IConfigurable) {
362         m_configuration.setConfigurable((IConfigurable) listener);
363       }
364       if (listener instanceof IHookable) {
365         m_configuration.setHookable((IHookable) listener);
366       }
367       if (listener instanceof IExecutionListener) {
368         IExecutionListener iel = (IExecutionListener) listener;
369         iel.onExecutionStart();
370         m_configuration.addExecutionListener(iel);
371       }
372     }
373   }
374 
375   /**
376    * Initialize meta groups
377    */
initMetaGroups(XmlTest xmlTest)378   private void initMetaGroups(XmlTest xmlTest) {
379     Map<String, List<String>> metaGroups = xmlTest.getMetaGroups();
380 
381     for (Map.Entry<String, List<String>> entry : metaGroups.entrySet()) {
382       addMetaGroup(entry.getKey(), entry.getValue());
383     }
384   }
385 
initRunInfo(final XmlTest xmlTest)386   private void initRunInfo(final XmlTest xmlTest) {
387     // Groups
388     m_xmlMethodSelector.setIncludedGroups(createGroups(m_xmlTest.getIncludedGroups()));
389     m_xmlMethodSelector.setExcludedGroups(createGroups(m_xmlTest.getExcludedGroups()));
390     m_xmlMethodSelector.setExpression(m_xmlTest.getExpression());
391 
392     // Methods
393     m_xmlMethodSelector.setXmlClasses(m_xmlTest.getXmlClasses());
394 
395     m_runInfo.addMethodSelector(m_xmlMethodSelector, 10);
396 
397     // Add user-specified method selectors (only class selectors, we can ignore
398     // script selectors here)
399     if (null != xmlTest.getMethodSelectors()) {
400       for (org.testng.xml.XmlMethodSelector selector : xmlTest.getMethodSelectors()) {
401         if (selector.getClassName() != null) {
402           IMethodSelector s = ClassHelper.createSelector(selector);
403 
404           m_runInfo.addMethodSelector(s, selector.getPriority());
405         }
406       }
407     }
408   }
409 
initMethods()410   private void initMethods() {
411 
412     //
413     // Calculate all the methods we need to invoke
414     //
415     List<ITestNGMethod> beforeClassMethods = Lists.newArrayList();
416     List<ITestNGMethod> testMethods = Lists.newArrayList();
417     List<ITestNGMethod> afterClassMethods = Lists.newArrayList();
418     List<ITestNGMethod> beforeSuiteMethods = Lists.newArrayList();
419     List<ITestNGMethod> afterSuiteMethods = Lists.newArrayList();
420     List<ITestNGMethod> beforeXmlTestMethods = Lists.newArrayList();
421     List<ITestNGMethod> afterXmlTestMethods = Lists.newArrayList();
422 
423     ClassInfoMap classMap = new ClassInfoMap(m_testClassesFromXml);
424     m_testClassFinder= new TestNGClassFinder(classMap,
425                                              null,
426                                              m_xmlTest,
427                                              m_configuration,
428                                              this);
429     ITestMethodFinder testMethodFinder
430       = new TestNGMethodFinder(m_runInfo, m_annotationFinder);
431 
432     m_runInfo.setTestMethods(testMethods);
433 
434     //
435     // Initialize TestClasses
436     //
437     IClass[] classes = m_testClassFinder.findTestClasses();
438 
439     for (IClass ic : classes) {
440 
441       // Create TestClass
442       ITestClass tc = new TestClass(ic,
443                                    testMethodFinder,
444                                    m_annotationFinder,
445                                    m_runInfo,
446                                    m_xmlTest,
447                                    classMap.getXmlClass(ic.getRealClass()));
448       m_classMap.put(ic.getRealClass(), tc);
449     }
450 
451     //
452     // Calculate groups methods
453     //
454     Map<String, List<ITestNGMethod>> beforeGroupMethods =
455         MethodGroupsHelper.findGroupsMethods(m_classMap.values(), true);
456     Map<String, List<ITestNGMethod>> afterGroupMethods =
457         MethodGroupsHelper.findGroupsMethods(m_classMap.values(), false);
458 
459     //
460     // Walk through all the TestClasses, store their method
461     // and initialize them with the correct ITestClass
462     //
463     for (ITestClass tc : m_classMap.values()) {
464       fixMethodsWithClass(tc.getTestMethods(), tc, testMethods);
465       fixMethodsWithClass(tc.getBeforeClassMethods(), tc, beforeClassMethods);
466       fixMethodsWithClass(tc.getBeforeTestMethods(), tc, null);
467       fixMethodsWithClass(tc.getAfterTestMethods(), tc, null);
468       fixMethodsWithClass(tc.getAfterClassMethods(), tc, afterClassMethods);
469       fixMethodsWithClass(tc.getBeforeSuiteMethods(), tc, beforeSuiteMethods);
470       fixMethodsWithClass(tc.getAfterSuiteMethods(), tc, afterSuiteMethods);
471       fixMethodsWithClass(tc.getBeforeTestConfigurationMethods(), tc, beforeXmlTestMethods);
472       fixMethodsWithClass(tc.getAfterTestConfigurationMethods(), tc, afterXmlTestMethods);
473       fixMethodsWithClass(tc.getBeforeGroupsMethods(), tc,
474           MethodHelper.uniqueMethodList(beforeGroupMethods.values()));
475       fixMethodsWithClass(tc.getAfterGroupsMethods(), tc,
476           MethodHelper.uniqueMethodList(afterGroupMethods.values()));
477     }
478 
479     //
480     // Sort the methods
481     //
482     m_beforeSuiteMethods = MethodHelper.collectAndOrderMethods(beforeSuiteMethods,
483                                                               false /* forTests */,
484                                                               m_runInfo,
485                                                               m_annotationFinder,
486                                                               true /* unique */,
487                                                               m_excludedMethods);
488 
489     m_beforeXmlTestMethods = MethodHelper.collectAndOrderMethods(beforeXmlTestMethods,
490                                                               false /* forTests */,
491                                                               m_runInfo,
492                                                               m_annotationFinder,
493                                                               true /* unique (CQ added by me)*/,
494                                                               m_excludedMethods);
495 
496     m_allTestMethods = MethodHelper.collectAndOrderMethods(testMethods,
497                                                                 true /* forTest? */,
498                                                                 m_runInfo,
499                                                                 m_annotationFinder,
500                                                                 false /* unique */,
501                                                                 m_excludedMethods);
502     m_classMethodMap = new ClassMethodMap(testMethods, m_xmlMethodSelector);
503 
504     m_afterXmlTestMethods = MethodHelper.collectAndOrderMethods(afterXmlTestMethods,
505                                                               false /* forTests */,
506                                                               m_runInfo,
507                                                               m_annotationFinder,
508                                                               true /* unique (CQ added by me)*/,
509                                                               m_excludedMethods);
510 
511     m_afterSuiteMethods = MethodHelper.collectAndOrderMethods(afterSuiteMethods,
512                                                               false /* forTests */,
513                                                               m_runInfo,
514                                                               m_annotationFinder,
515                                                               true /* unique */,
516                                                               m_excludedMethods);
517     // shared group methods
518     m_groupMethods = new ConfigurationGroupMethods(m_allTestMethods, beforeGroupMethods, afterGroupMethods);
519 
520 
521   }
522 
fixMethodsWithClass(ITestNGMethod[] methods, ITestClass testCls, List<ITestNGMethod> methodList)523   private void fixMethodsWithClass(ITestNGMethod[] methods,
524                                    ITestClass testCls,
525                                    List<ITestNGMethod> methodList) {
526     for (ITestNGMethod itm : methods) {
527       itm.setTestClass(testCls);
528 
529       if (methodList != null) {
530         methodList.add(itm);
531       }
532     }
533   }
534 
getTestClasses()535   public Collection<ITestClass> getTestClasses() {
536     return m_classMap.values();
537   }
538 
setTestName(String name)539   public void setTestName(String name) {
540     m_testName = name;
541   }
542 
setOutputDirectory(String od)543   public void setOutputDirectory(String od) {
544     m_outputDirectory= od;
545 //  FIX: empty directories were created
546 //    if (od == null) { m_outputDirectory = null; return; } //for maven2
547 //    File file = new File(od);
548 //    file.mkdirs();
549 //    m_outputDirectory= file.getAbsolutePath();
550   }
551 
addMetaGroup(String name, List<String> groupNames)552   private void addMetaGroup(String name, List<String> groupNames) {
553     m_metaGroups.put(name, groupNames);
554   }
555 
556   /**
557    * Calculate the transitive closure of all the MetaGroups
558    *
559    * @param groups
560    * @param unfinishedGroups
561    * @param result           The transitive closure containing all the groups found
562    */
collectGroups(String[] groups, List<String> unfinishedGroups, Map<String, String> result)563   private void collectGroups(String[] groups,
564                              List<String> unfinishedGroups,
565                              Map<String, String> result) {
566     for (String gn : groups) {
567       List<String> subGroups = m_metaGroups.get(gn);
568       if (null != subGroups) {
569 
570         for (String sg : subGroups) {
571           if (null == result.get(sg)) {
572             result.put(sg, sg);
573             unfinishedGroups.add(sg);
574           }
575         }
576       }
577     }
578   }
579 
createGroups(List<String> groups)580   private Map<String, String> createGroups(List<String> groups) {
581     return createGroups(groups.toArray(new String[groups.size()]));
582   }
583 
createGroups(String[] groups)584   private Map<String, String> createGroups(String[] groups) {
585     Map<String, String> result = Maps.newHashMap();
586 
587     // Groups that were passed on the command line
588     for (String group : groups) {
589       result.put(group, group);
590     }
591 
592     // See if we have any MetaGroups and
593     // expand them if they match one of the groups
594     // we have just been passed
595     List<String> unfinishedGroups = Lists.newArrayList();
596 
597     if (m_metaGroups.size() > 0) {
598       collectGroups(groups, unfinishedGroups, result);
599 
600       // Do we need to loop over unfinished groups?
601       while (unfinishedGroups.size() > 0) {
602         String[] uGroups = unfinishedGroups.toArray(new String[unfinishedGroups.size()]);
603         unfinishedGroups = Lists.newArrayList();
604         collectGroups(uGroups, unfinishedGroups, result);
605       }
606     }
607 
608     //    Utils.dumpMap(result);
609     return result;
610   }
611 
612   /**
613    * The main entry method for TestRunner.
614    *
615    * This is where all the hard work is done:
616    * - Invoke configuration methods
617    * - Invoke test methods
618    * - Catch exceptions
619    * - Collect results
620    * - Invoke listeners
621    * - etc...
622    */
run()623   public void run() {
624     beforeRun();
625 
626     try {
627       XmlTest test= getTest();
628       if(test.isJUnit()) {
629         privateRunJUnit(test);
630       }
631       else {
632         privateRun(test);
633       }
634     }
635     finally {
636       afterRun();
637     }
638   }
639 
640   /** Before run preparements. */
beforeRun()641   private void beforeRun() {
642     //
643     // Log the start date
644     //
645     m_startDate = new Date(System.currentTimeMillis());
646 
647     // Log start
648     logStart();
649 
650     // Invoke listeners
651     fireEvent(true /*start*/);
652 
653     // invoke @BeforeTest
654     ITestNGMethod[] testConfigurationMethods= getBeforeTestConfigurationMethods();
655     if(null != testConfigurationMethods && testConfigurationMethods.length > 0) {
656       m_invoker.invokeConfigurations(null,
657                                      testConfigurationMethods,
658                                      m_xmlTest.getSuite(),
659                                      m_xmlTest.getAllParameters(),
660                                      null, /* no parameter values */
661                                      null /* instance */);
662     }
663   }
664 
privateRunJUnit(XmlTest xmlTest)665   private void privateRunJUnit(XmlTest xmlTest) {
666     final ClassInfoMap cim = new ClassInfoMap(m_testClassesFromXml, false);
667     final Set<Class<?>> classes = cim.getClasses();
668     final List<ITestNGMethod> runMethods = Lists.newArrayList();
669     List<IWorker<ITestNGMethod>> workers = Lists.newArrayList();
670     // FIXME: directly referencing JUnitTestRunner which uses JUnit classes
671     // may result in an class resolution exception under different JVMs
672     // The resolution process is not specified in the JVM spec with a specific implementation,
673     // so it can be eager => failure
674     workers.add(new IWorker<ITestNGMethod>() {
675       /**
676        * @see TestMethodWorker#getTimeOut()
677        */
678       @Override
679       public long getTimeOut() {
680         return 0;
681       }
682 
683       /**
684        * @see java.lang.Runnable#run()
685        */
686       @Override
687       public void run() {
688         for(Class<?> tc: classes) {
689           List<XmlInclude> includedMethods = cim.getXmlClass(tc).getIncludedMethods();
690           List<String> methods = Lists.newArrayList();
691           for (XmlInclude inc: includedMethods) {
692               methods.add(inc.getName());
693           }
694           IJUnitTestRunner tr= ClassHelper.createTestRunner(TestRunner.this);
695           tr.setInvokedMethodListeners(m_invokedMethodListeners);
696           try {
697             tr.run(tc, methods.toArray(new String[methods.size()]));
698           }
699           catch(Exception ex) {
700             ex.printStackTrace();
701           }
702           finally {
703             runMethods.addAll(tr.getTestMethods());
704           }
705         }
706       }
707 
708       @Override
709       public List<ITestNGMethod> getTasks() {
710         throw new TestNGException("JUnit not supported");
711       }
712 
713       @Override
714       public int getPriority() {
715         if (m_allTestMethods.length == 1) {
716           return m_allTestMethods[0].getPriority();
717         } else {
718           return 0;
719         }
720       }
721 
722       @Override
723       public int compareTo(IWorker<ITestNGMethod> other) {
724         return getPriority() - other.getPriority();
725       }
726     });
727 
728     runJUnitWorkers(workers);
729     m_allTestMethods= runMethods.toArray(new ITestNGMethod[runMethods.size()]);
730   }
731 
732   private static final EnumSet<XmlSuite.ParallelMode> PRIVATE_RUN_PARALLEL_MODES
733       = EnumSet.of(XmlSuite.ParallelMode.METHODS, XmlSuite.ParallelMode.TRUE,
734                    XmlSuite.ParallelMode.CLASSES, XmlSuite.ParallelMode.INSTANCES);
735   /**
736    * Main method that create a graph of methods and then pass it to the
737    * graph executor to run them.
738    */
privateRun(XmlTest xmlTest)739   private void privateRun(XmlTest xmlTest) {
740     XmlSuite.ParallelMode parallelMode = xmlTest.getParallel();
741     boolean parallel = PRIVATE_RUN_PARALLEL_MODES.contains(parallelMode);
742 
743     {
744       // parallel
745       int threadCount = parallel ? xmlTest.getThreadCount() : 1;
746       // Make sure we create a graph based on the intercepted methods, otherwise an interceptor
747       // removing methods would cause the graph never to terminate (because it would expect
748       // termination from methods that never get invoked).
749       DynamicGraph<ITestNGMethod> graph = createDynamicGraph(intercept(m_allTestMethods));
750       if (parallel) {
751         if (graph.getNodeCount() > 0) {
752           GraphThreadPoolExecutor<ITestNGMethod> executor =
753                   new GraphThreadPoolExecutor<>(graph, this,
754                           threadCount, threadCount, 0, TimeUnit.MILLISECONDS,
755                           new LinkedBlockingQueue<Runnable>());
756           executor.run();
757           try {
758             long timeOut = m_xmlTest.getTimeOut(XmlTest.DEFAULT_TIMEOUT_MS);
759             Utils.log("TestRunner", 2, "Starting executor for test " + m_xmlTest.getName()
760                 + " with time out:" + timeOut + " milliseconds.");
761             executor.awaitTermination(timeOut, TimeUnit.MILLISECONDS);
762             executor.shutdownNow();
763           } catch (InterruptedException handled) {
764             handled.printStackTrace();
765             Thread.currentThread().interrupt();
766           }
767         }
768       } else {
769         boolean debug = false;
770         List<ITestNGMethod> freeNodes = graph.getFreeNodes();
771         if (debug) {
772           System.out.println("Free nodes:" + freeNodes);
773         }
774 
775         if (graph.getNodeCount() > 0 && freeNodes.isEmpty()) {
776           throw new TestNGException("No free nodes found in:" + graph);
777         }
778 
779         while (! freeNodes.isEmpty()) {
780           List<IWorker<ITestNGMethod>> runnables = createWorkers(freeNodes);
781           for (IWorker<ITestNGMethod> r : runnables) {
782             r.run();
783           }
784           graph.setStatus(freeNodes, Status.FINISHED);
785           freeNodes = graph.getFreeNodes();
786           if (debug) {
787             System.out.println("Free nodes:" + freeNodes);
788           }
789         }
790       }
791     }
792   }
793 
794   /**
795    * Apply the method interceptor (if applicable) to the list of methods.
796    */
intercept(ITestNGMethod[] methods)797   private ITestNGMethod[] intercept(ITestNGMethod[] methods) {
798     List<IMethodInstance> methodInstances = methodsToMethodInstances(Arrays.asList(methods));
799 
800     // add built-in interceptor (PreserveOrderMethodInterceptor or InstanceOrderingMethodInterceptor at the end of the list
801     m_methodInterceptors.add(builtinInterceptor);
802     for (IMethodInterceptor m_methodInterceptor : m_methodInterceptors) {
803       methodInstances = m_methodInterceptor.intercept(methodInstances, this);
804     }
805 
806     List<ITestNGMethod> result = Lists.newArrayList();
807     for (IMethodInstance imi : methodInstances) {
808       result.add(imi.getMethod());
809     }
810 
811     //Since an interceptor is involved, we would need to ensure that the ClassMethodMap object is in sync with the
812     //output of the interceptor, else @AfterClass doesn't get executed at all when interceptors are involved.
813     //so let's update the current classMethodMap object with the list of methods obtained from the interceptor.
814     this.m_classMethodMap = new ClassMethodMap(result, null);
815 
816     return result.toArray(new ITestNGMethod[result.size()]);
817   }
818 
819   /**
820    * Create a list of workers to run the methods passed in parameter.
821    * Each test method is run in its own worker except in the following cases:
822    * - The method belongs to a class that has @Test(sequential=true)
823    * - The parallel attribute is set to "classes"
824    * In both these cases, all the methods belonging to that class will then
825    * be put in the same worker in order to run in the same thread.
826    */
827   @Override
createWorkers(List<ITestNGMethod> methods)828   public List<IWorker<ITestNGMethod>> createWorkers(List<ITestNGMethod> methods) {
829     List<IWorker<ITestNGMethod>> result;
830     if (XmlSuite.ParallelMode.INSTANCES.equals(m_xmlTest.getParallel())) {
831       result = createInstanceBasedParallelWorkers(methods);
832     } else {
833       result = createClassBasedParallelWorkers(methods);
834     }
835     return result;
836   }
837 
838   /**
839    * Create workers for parallel="classes" and similar cases.
840    */
createClassBasedParallelWorkers(List<ITestNGMethod> methods)841   private List<IWorker<ITestNGMethod>> createClassBasedParallelWorkers(List<ITestNGMethod> methods) {
842     List<IWorker<ITestNGMethod>> result = Lists.newArrayList();
843     // Methods that belong to classes with a sequential=true or parallel=classes
844     // attribute must all be run in the same worker
845     Set<Class> sequentialClasses = Sets.newHashSet();
846     for (ITestNGMethod m : methods) {
847       Class<? extends ITestClass> cls = m.getRealClass();
848       org.testng.annotations.ITestAnnotation test =
849           m_annotationFinder.findAnnotation(cls, org.testng.annotations.ITestAnnotation.class);
850 
851       // If either sequential=true or parallel=classes, mark this class sequential
852       if (test != null && (test.getSequential() || test.getSingleThreaded()) ||
853           XmlSuite.ParallelMode.CLASSES.equals(m_xmlTest.getParallel())) {
854         sequentialClasses.add(cls);
855       }
856     }
857 
858     List<IMethodInstance> methodInstances = Lists.newArrayList();
859     for (ITestNGMethod tm : methods) {
860       methodInstances.addAll(methodsToMultipleMethodInstances(tm));
861     }
862 
863 
864     Map<String, String> params = m_xmlTest.getAllParameters();
865 
866     Set<Class<?>> processedClasses = Sets.newHashSet();
867     for (IMethodInstance im : methodInstances) {
868       Class<?> c = im.getMethod().getTestClass().getRealClass();
869       if (sequentialClasses.contains(c)) {
870         if (!processedClasses.contains(c)) {
871           processedClasses.add(c);
872           if (System.getProperty("experimental") != null) {
873             List<List<IMethodInstance>> instances = createInstances(methodInstances);
874             for (List<IMethodInstance> inst : instances) {
875               TestMethodWorker worker = createTestMethodWorker(inst, params, c);
876               result.add(worker);
877             }
878           }
879           else {
880             // Sequential class: all methods in one worker
881             TestMethodWorker worker = createTestMethodWorker(methodInstances, params, c);
882             result.add(worker);
883           }
884         }
885       }
886       else {
887         // Parallel class: each method in its own worker
888         TestMethodWorker worker = createTestMethodWorker(Arrays.asList(im), params, c);
889         result.add(worker);
890       }
891     }
892 
893     // Sort by priorities
894     Collections.sort(result);
895     return result;
896   }
897 
898 
899   /**
900    * Create workers for parallel="instances".
901    */
902   private List<IWorker<ITestNGMethod>>
createInstanceBasedParallelWorkers(List<ITestNGMethod> methods)903       createInstanceBasedParallelWorkers(List<ITestNGMethod> methods) {
904     List<IWorker<ITestNGMethod>> result = Lists.newArrayList();
905     ListMultiMap<Object, ITestNGMethod> lmm = Maps.newListMultiMap();
906     for (ITestNGMethod m : methods) {
907       lmm.put(m.getInstance(), m);
908     }
909     for (Map.Entry<Object, List<ITestNGMethod>> es : lmm.entrySet()) {
910       List<IMethodInstance> methodInstances = Lists.newArrayList();
911       for (ITestNGMethod m : es.getValue()) {
912         methodInstances.add(new MethodInstance(m));
913       }
914       TestMethodWorker tmw = new TestMethodWorker(m_invoker,
915           methodInstances.toArray(new IMethodInstance[methodInstances.size()]),
916           m_xmlTest.getSuite(),
917           m_xmlTest.getAllParameters(),
918           m_groupMethods,
919           m_classMethodMap,
920           this,
921           m_classListeners);
922       result.add(tmw);
923     }
924 
925     return result;
926   }
927 
createInstances(List<IMethodInstance> methodInstances)928   private List<List<IMethodInstance>> createInstances(List<IMethodInstance> methodInstances) {
929     Map<Object, List<IMethodInstance>> map = Maps.newHashMap();
930 //    MapList<IMethodInstance[], Object> map = new MapList<IMethodInstance[], Object>();
931     for (IMethodInstance imi : methodInstances) {
932       for (Object o : imi.getInstances()) {
933         System.out.println(o);
934         List<IMethodInstance> l = map.get(o);
935         if (l == null) {
936           l = Lists.newArrayList();
937           map.put(o, l);
938         }
939         l.add(imi);
940       }
941 //      for (Object instance : imi.getInstances()) {
942 //        map.put(imi, instance);
943 //      }
944     }
945 //    return map.getKeys();
946 //    System.out.println(map);
947     return new ArrayList<>(map.values());
948   }
949 
createTestMethodWorker( List<IMethodInstance> methodInstances, Map<String, String> params, Class<?> c)950   private TestMethodWorker createTestMethodWorker(
951       List<IMethodInstance> methodInstances, Map<String, String> params,
952       Class<?> c) {
953     return new TestMethodWorker(m_invoker,
954         findClasses(methodInstances, c),
955         m_xmlTest.getSuite(),
956         params,
957         m_groupMethods,
958         m_classMethodMap,
959         this,
960         m_classListeners);
961   }
962 
findClasses(List<IMethodInstance> methodInstances, Class<?> c)963   private IMethodInstance[] findClasses(List<IMethodInstance> methodInstances, Class<?> c) {
964     List<IMethodInstance> result = Lists.newArrayList();
965     for (IMethodInstance mi : methodInstances) {
966       if (mi.getMethod().getTestClass().getRealClass() == c) {
967         result.add(mi);
968       }
969     }
970     return result.toArray(new IMethodInstance[result.size()]);
971   }
972 
973   /**
974    * @@@ remove this
975    */
methodsToMultipleMethodInstances(ITestNGMethod... sl)976   private List<MethodInstance> methodsToMultipleMethodInstances(ITestNGMethod... sl) {
977     List<MethodInstance> vResult = Lists.newArrayList();
978     for (ITestNGMethod m : sl) {
979       vResult.add(new MethodInstance(m));
980     }
981 
982     return vResult;
983   }
984 
methodsToMethodInstances(List<ITestNGMethod> sl)985   private List<IMethodInstance> methodsToMethodInstances(List<ITestNGMethod> sl) {
986     List<IMethodInstance> result = new ArrayList<>();
987       for (ITestNGMethod iTestNGMethod : sl) {
988         result.add(new MethodInstance(iTestNGMethod));
989       }
990     return result;
991   }
992 
993   //
994   // Invoke the workers
995   //
996   private static final EnumSet<XmlSuite.ParallelMode> WORKERS_PARALLEL_MODES
997       = EnumSet.of(XmlSuite.ParallelMode.METHODS, XmlSuite.ParallelMode.TRUE,
998                    XmlSuite.ParallelMode.CLASSES);
runJUnitWorkers(List<? extends IWorker<ITestNGMethod>> workers)999   private void runJUnitWorkers(List<? extends IWorker<ITestNGMethod>> workers) {
1000       //
1001       // Sequential run
1002       //
1003       for (IWorker<ITestNGMethod> tmw : workers) {
1004         tmw.run();
1005       }
1006   }
1007 
afterRun()1008   private void afterRun() {
1009     // invoke @AfterTest
1010     ITestNGMethod[] testConfigurationMethods= getAfterTestConfigurationMethods();
1011     if(null != testConfigurationMethods && testConfigurationMethods.length > 0) {
1012       m_invoker.invokeConfigurations(null,
1013                                      testConfigurationMethods,
1014                                      m_xmlTest.getSuite(),
1015                                      m_xmlTest.getAllParameters(),
1016                                      null, /* no parameter values */
1017                                      null /* instance */);
1018     }
1019 
1020     //
1021     // Log the end date
1022     //
1023     m_endDate = new Date(System.currentTimeMillis());
1024 
1025     if (getVerbose() >= 3) {
1026       dumpInvokedMethods();
1027     }
1028 
1029     // Invoke listeners
1030     fireEvent(false /*stop*/);
1031 
1032     // Statistics
1033 //    logResults();
1034   }
1035 
createDynamicGraph(ITestNGMethod[] methods)1036   private DynamicGraph<ITestNGMethod> createDynamicGraph(ITestNGMethod[] methods) {
1037     DynamicGraph<ITestNGMethod> result = new DynamicGraph<>();
1038     result.setComparator(new Comparator<ITestNGMethod>() {
1039       @Override
1040       public int compare(ITestNGMethod o1, ITestNGMethod o2) {
1041         return o1.getPriority() - o2.getPriority();
1042       }
1043     });
1044 
1045     DependencyMap dependencyMap = new DependencyMap(methods);
1046 
1047     // Keep track of whether we have group dependencies. If we do, preserve-order needs
1048     // to be ignored since group dependencies create inter-class dependencies which can
1049     // end up creating cycles when combined with preserve-order.
1050     boolean hasDependencies = false;
1051     for (ITestNGMethod m : methods) {
1052       result.addNode(m);
1053 
1054       // Dependent methods
1055       {
1056         String[] dependentMethods = m.getMethodsDependedUpon();
1057         if (dependentMethods != null) {
1058           for (String d : dependentMethods) {
1059             ITestNGMethod dm = dependencyMap.getMethodDependingOn(d, m);
1060             if (m != dm){
1061             	result.addEdge(m, dm);
1062             }
1063           }
1064         }
1065       }
1066 
1067       // Dependent groups
1068       {
1069         String[] dependentGroups = m.getGroupsDependedUpon();
1070         for (String d : dependentGroups) {
1071           hasDependencies = true;
1072           List<ITestNGMethod> dg = dependencyMap.getMethodsThatBelongTo(d, m);
1073           if (dg == null) {
1074             throw new TestNGException("Method \"" + m
1075                 + "\" depends on nonexistent group \"" + d + "\"");
1076           }
1077           for (ITestNGMethod ddm : dg) {
1078             result.addEdge(m, ddm);
1079           }
1080         }
1081       }
1082     }
1083 
1084     // Preserve order
1085     // Don't preserve the ordering if we're running in parallel, otherwise the suite will
1086     // create multiple threads but these threads will be created one after the other,
1087     // giving the impression of parallelism (multiple thread id's) while still running
1088     // sequentially.
1089     if (! hasDependencies
1090         && getCurrentXmlTest().getParallel() == XmlSuite.ParallelMode.FALSE
1091         && "true".equalsIgnoreCase(getCurrentXmlTest().getPreserveOrder())) {
1092       // If preserve-order was specified and the class order is A, B
1093       // create a new set of dependencies where each method of B depends
1094       // on all the methods of A
1095       ListMultiMap<ITestNGMethod, ITestNGMethod> classDependencies
1096           = createClassDependencies(methods, getCurrentXmlTest());
1097 
1098       for (Map.Entry<ITestNGMethod, List<ITestNGMethod>> es : classDependencies.entrySet()) {
1099         for (ITestNGMethod dm : es.getValue()) {
1100           result.addEdge(dm, es.getKey());
1101         }
1102       }
1103     }
1104 
1105     // Group by instances
1106     if (getCurrentXmlTest().getGroupByInstances()) {
1107       ListMultiMap<ITestNGMethod, ITestNGMethod> instanceDependencies
1108           = createInstanceDependencies(methods, getCurrentXmlTest());
1109 
1110       for (Map.Entry<ITestNGMethod, List<ITestNGMethod>> es : instanceDependencies.entrySet()) {
1111         for (ITestNGMethod dm : es.getValue()) {
1112           result.addEdge(dm, es.getKey());
1113         }
1114       }
1115 
1116     }
1117 
1118     return result;
1119   }
1120 
createInstanceDependencies( ITestNGMethod[] methods, XmlTest currentXmlTest)1121   private ListMultiMap<ITestNGMethod, ITestNGMethod> createInstanceDependencies(
1122       ITestNGMethod[] methods, XmlTest currentXmlTest)
1123   {
1124     ListMultiMap<Object, ITestNGMethod> instanceMap = Maps.newListMultiMap();
1125     for (ITestNGMethod m : methods) {
1126       instanceMap.put(m.getInstance(), m);
1127     }
1128 
1129     ListMultiMap<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
1130     Object previousInstance = null;
1131     for (Map.Entry<Object, List<ITestNGMethod>> es : instanceMap.entrySet()) {
1132       if (previousInstance == null) {
1133         previousInstance = es.getKey();
1134       } else {
1135         List<ITestNGMethod> previousMethods = instanceMap.get(previousInstance);
1136         Object currentInstance = es.getKey();
1137         List<ITestNGMethod> currentMethods = instanceMap.get(currentInstance);
1138         // Make all the methods from the current instance depend on the methods of
1139         // the previous instance
1140         for (ITestNGMethod cm : currentMethods) {
1141           for (ITestNGMethod pm : previousMethods) {
1142             result.put(cm, pm);
1143           }
1144         }
1145         previousInstance = currentInstance;
1146       }
1147     }
1148 
1149     return result;
1150   }
1151 
createClassDependencies( ITestNGMethod[] methods, XmlTest test)1152   private ListMultiMap<ITestNGMethod, ITestNGMethod> createClassDependencies(
1153       ITestNGMethod[] methods, XmlTest test)
1154   {
1155     Map<String, List<ITestNGMethod>> classes = Maps.newHashMap();
1156     // Note: use a List here to preserve the ordering but make sure
1157     // we don't add the same class twice
1158     List<XmlClass> sortedClasses = Lists.newArrayList();
1159 
1160     for (XmlClass c : test.getXmlClasses()) {
1161       classes.put(c.getName(), new ArrayList<ITestNGMethod>());
1162       if (! sortedClasses.contains(c)) sortedClasses.add(c);
1163     }
1164 
1165     // Sort the classes based on their order of appearance in the XML
1166     Collections.sort(sortedClasses, new Comparator<XmlClass>() {
1167       @Override
1168       public int compare(XmlClass arg0, XmlClass arg1) {
1169         return arg0.getIndex() - arg1.getIndex();
1170       }
1171     });
1172 
1173     Map<String, Integer> indexedClasses1 = Maps.newHashMap();
1174     Map<Integer, String> indexedClasses2 = Maps.newHashMap();
1175     int i = 0;
1176     for (XmlClass c : sortedClasses) {
1177       indexedClasses1.put(c.getName(), i);
1178       indexedClasses2.put(i, c.getName());
1179       i++;
1180     }
1181 
1182     ListMultiMap<String, ITestNGMethod> methodsFromClass = Maps.newListMultiMap();
1183     for (ITestNGMethod m : methods) {
1184       methodsFromClass.put(m.getTestClass().getName(), m);
1185     }
1186 
1187     ListMultiMap<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
1188     for (ITestNGMethod m : methods) {
1189       String name = m.getTestClass().getName();
1190       Integer index = indexedClasses1.get(name);
1191       // The index could be null if the classes listed in the XML are different
1192       // from the methods being run (e.g. the .xml only contains a factory that
1193       // instantiates methods from a different class). In this case, we cannot
1194       // perform any ordering.
1195       if (index != null && index > 0) {
1196         // Make this method depend on all the methods of the class in the previous
1197         // index
1198         String classDependedUpon = indexedClasses2.get(index - 1);
1199         List<ITestNGMethod> methodsDependedUpon = methodsFromClass.get(classDependedUpon);
1200         if (methodsDependedUpon != null) {
1201           for (ITestNGMethod mdu : methodsDependedUpon) {
1202             result.put(mdu, m);
1203           }
1204         }
1205       }
1206     }
1207 
1208     return result;
1209   }
1210 
1211   /**
1212    * Logs the beginning of the {@link #beforeRun()} .
1213    */
logStart()1214   private void logStart() {
1215     log(3,
1216         "Running test " + m_testName + " on " + m_classMap.size() + " " + " classes, "
1217         + " included groups:[" + mapToString(m_xmlMethodSelector.getIncludedGroups())
1218         + "] excluded groups:[" + mapToString(m_xmlMethodSelector.getExcludedGroups()) + "]");
1219 
1220     if (getVerbose() >= 3) {
1221       for (ITestClass tc : m_classMap.values()) {
1222         ((TestClass) tc).dump();
1223       }
1224     }
1225   }
1226 
1227   /**
1228    * Trigger the start/finish event.
1229    *
1230    * @param isStart <tt>true</tt> if the event is for start, <tt>false</tt> if the
1231    *                event is for finish
1232    */
fireEvent(boolean isStart)1233   private void fireEvent(boolean isStart) {
1234     for (ITestListener itl : m_testListeners) {
1235       if (isStart) {
1236         itl.onStart(this);
1237       }
1238       else {
1239         itl.onFinish(this);
1240       }
1241     }
1242   }
1243 
1244   /////
1245   // ITestContext
1246   //
1247   @Override
getName()1248   public String getName() {
1249     return m_testName;
1250   }
1251 
1252   /**
1253    * @return Returns the startDate.
1254    */
1255   @Override
getStartDate()1256   public Date getStartDate() {
1257     return m_startDate;
1258   }
1259 
1260   /**
1261    * @return Returns the endDate.
1262    */
1263   @Override
getEndDate()1264   public Date getEndDate() {
1265     return m_endDate;
1266   }
1267 
1268   @Override
getPassedTests()1269   public IResultMap getPassedTests() {
1270     return m_passedTests;
1271   }
1272 
1273   @Override
getSkippedTests()1274   public IResultMap getSkippedTests() {
1275     return m_skippedTests;
1276   }
1277 
1278   @Override
getFailedTests()1279   public IResultMap getFailedTests() {
1280     return m_failedTests;
1281   }
1282 
1283   @Override
getFailedButWithinSuccessPercentageTests()1284   public IResultMap getFailedButWithinSuccessPercentageTests() {
1285     return m_failedButWithinSuccessPercentageTests;
1286   }
1287 
1288   @Override
getIncludedGroups()1289   public String[] getIncludedGroups() {
1290     Map<String, String> ig= m_xmlMethodSelector.getIncludedGroups();
1291     String[] result= ig.values().toArray((new String[ig.size()]));
1292 
1293     return result;
1294   }
1295 
1296   @Override
getExcludedGroups()1297   public String[] getExcludedGroups() {
1298     Map<String, String> eg= m_xmlMethodSelector.getExcludedGroups();
1299     String[] result= eg.values().toArray((new String[eg.size()]));
1300 
1301     return result;
1302   }
1303 
1304   @Override
getOutputDirectory()1305   public String getOutputDirectory() {
1306     return m_outputDirectory;
1307   }
1308 
1309   /**
1310    * @return Returns the suite.
1311    */
1312   @Override
getSuite()1313   public ISuite getSuite() {
1314     return m_suite;
1315   }
1316 
1317   @Override
getAllTestMethods()1318   public ITestNGMethod[] getAllTestMethods() {
1319     return m_allTestMethods;
1320   }
1321 
1322 
1323   @Override
getHost()1324   public String getHost() {
1325     return m_host;
1326   }
1327 
1328   @Override
getExcludedMethods()1329   public Collection<ITestNGMethod> getExcludedMethods() {
1330     Map<ITestNGMethod, ITestNGMethod> vResult = Maps.newHashMap();
1331 
1332     for (ITestNGMethod m : m_excludedMethods) {
1333       vResult.put(m, m);
1334     }
1335 
1336     return vResult.keySet();
1337   }
1338 
1339   /**
1340    * @see org.testng.ITestContext#getFailedConfigurations()
1341    */
1342   @Override
getFailedConfigurations()1343   public IResultMap getFailedConfigurations() {
1344     return m_failedConfigurations;
1345   }
1346 
1347   /**
1348    * @see org.testng.ITestContext#getPassedConfigurations()
1349    */
1350   @Override
getPassedConfigurations()1351   public IResultMap getPassedConfigurations() {
1352     return m_passedConfigurations;
1353   }
1354 
1355   /**
1356    * @see org.testng.ITestContext#getSkippedConfigurations()
1357    */
1358   @Override
getSkippedConfigurations()1359   public IResultMap getSkippedConfigurations() {
1360     return m_skippedConfigurations;
1361   }
1362 
1363   //
1364   // ITestContext
1365   /////
1366 
1367   /////
1368   // ITestResultNotifier
1369   //
1370 
1371   @Override
addPassedTest(ITestNGMethod tm, ITestResult tr)1372   public void addPassedTest(ITestNGMethod tm, ITestResult tr) {
1373     m_passedTests.addResult(tr, tm);
1374   }
1375 
1376   @Override
getPassedTests(ITestNGMethod tm)1377   public Set<ITestResult> getPassedTests(ITestNGMethod tm) {
1378     return m_passedTests.getResults(tm);
1379   }
1380 
1381   @Override
getFailedTests(ITestNGMethod tm)1382   public Set<ITestResult> getFailedTests(ITestNGMethod tm) {
1383     return m_failedTests.getResults(tm);
1384   }
1385 
1386   @Override
getSkippedTests(ITestNGMethod tm)1387   public Set<ITestResult> getSkippedTests(ITestNGMethod tm) {
1388     return m_skippedTests.getResults(tm);
1389   }
1390 
1391   @Override
addSkippedTest(ITestNGMethod tm, ITestResult tr)1392   public void addSkippedTest(ITestNGMethod tm, ITestResult tr) {
1393     m_skippedTests.addResult(tr, tm);
1394   }
1395 
1396   @Override
addInvokedMethod(InvokedMethod im)1397   public void addInvokedMethod(InvokedMethod im) {
1398     synchronized(m_invokedMethods) {
1399       m_invokedMethods.add(im);
1400     }
1401   }
1402 
1403   @Override
addFailedTest(ITestNGMethod testMethod, ITestResult result)1404   public void addFailedTest(ITestNGMethod testMethod, ITestResult result) {
1405     logFailedTest(testMethod, result, false /* withinSuccessPercentage */);
1406   }
1407 
1408   @Override
addFailedButWithinSuccessPercentageTest(ITestNGMethod testMethod, ITestResult result)1409   public void addFailedButWithinSuccessPercentageTest(ITestNGMethod testMethod,
1410                                                       ITestResult result) {
1411     logFailedTest(testMethod, result, true /* withinSuccessPercentage */);
1412   }
1413 
1414   @Override
getTest()1415   public XmlTest getTest() {
1416     return m_xmlTest;
1417   }
1418 
1419   @Override
getTestListeners()1420   public List<ITestListener> getTestListeners() {
1421     return m_testListeners;
1422   }
1423 
1424   @Override
getConfigurationListeners()1425   public List<IConfigurationListener> getConfigurationListeners() {
1426     return Lists.<IConfigurationListener>newArrayList(m_configurationListeners);
1427   }
1428   //
1429   // ITestResultNotifier
1430   /////
1431 
logFailedTest(ITestNGMethod method, ITestResult tr, boolean withinSuccessPercentage)1432   private void logFailedTest(ITestNGMethod method,
1433                              ITestResult tr,
1434                              boolean withinSuccessPercentage) {
1435     /*
1436      * We should not remove a passed method from m_passedTests so that we can
1437      * account for the passed instances of this test method.
1438      */
1439     //m_passedTests.removeResult(method);
1440     if (withinSuccessPercentage) {
1441       m_failedButWithinSuccessPercentageTests.addResult(tr, method);
1442     }
1443     else {
1444       m_failedTests.addResult(tr, method);
1445     }
1446   }
1447 
mapToString(Map<?, ?> m)1448   private String mapToString(Map<?, ?> m) {
1449     StringBuffer result= new StringBuffer();
1450     for (Object o : m.values()) {
1451       result.append(o.toString()).append(" ");
1452     }
1453 
1454     return result.toString();
1455   }
1456 
log(int level, String s)1457   private void log(int level, String s) {
1458     Utils.log("TestRunner", level, s);
1459   }
1460 
getVerbose()1461   public static int getVerbose() {
1462     return m_verbose;
1463   }
1464 
setVerbose(int n)1465   public void setVerbose(int n) {
1466     m_verbose = n;
1467   }
1468 
log(String s)1469   private void log(String s) {
1470     Utils.log("TestRunner", 2, s);
1471   }
1472 
1473   /////
1474   // Listeners
1475   //
addListener(Object listener)1476   public void addListener(Object listener) {
1477     if(listener instanceof ITestListener) {
1478       addTestListener((ITestListener) listener);
1479     }
1480     if(listener instanceof IConfigurationListener) {
1481       addConfigurationListener((IConfigurationListener) listener);
1482     }
1483     if(listener instanceof IClassListener) {
1484       addClassListener((IClassListener) listener);
1485     }
1486   }
1487 
addTestListener(ITestListener il)1488   public void addTestListener(ITestListener il) {
1489     m_testListeners.add(il);
1490   }
1491 
addClassListener(IClassListener cl)1492   public void addClassListener(IClassListener cl) {
1493     m_classListeners.add(cl);
1494   }
1495 
addConfigurationListener(IConfigurationListener icl)1496   void addConfigurationListener(IConfigurationListener icl) {
1497     m_configurationListeners.add(icl);
1498   }
1499   //
1500   // Listeners
1501   /////
1502 
1503   private final List<InvokedMethod> m_invokedMethods = Lists.newArrayList();
1504 
dumpInvokedMethods()1505   private void dumpInvokedMethods() {
1506     System.out.println("===== Invoked methods");
1507     for (IInvokedMethod im : m_invokedMethods) {
1508       if (im.isTestMethod()) {
1509         System.out.print("    ");
1510       }
1511       else if (im.isConfigurationMethod()) {
1512         System.out.print("  ");
1513       }
1514       else {
1515         continue;
1516       }
1517       System.out.println("" + im);
1518     }
1519     System.out.println("=====");
1520   }
1521 
getInvokedMethods()1522   public List<ITestNGMethod> getInvokedMethods() {
1523     List<ITestNGMethod> result= Lists.newArrayList();
1524     synchronized(m_invokedMethods) {
1525       for (IInvokedMethod im : m_invokedMethods) {
1526         ITestNGMethod tm= im.getTestMethod();
1527         tm.setDate(im.getDate());
1528         result.add(tm);
1529       }
1530     }
1531 
1532     return result;
1533   }
1534 
1535   private IResultMap m_passedConfigurations= new ResultMap();
1536   private IResultMap m_skippedConfigurations= new ResultMap();
1537   private IResultMap m_failedConfigurations= new ResultMap();
1538 
1539   private class ConfigurationListener implements IConfigurationListener2 {
1540     @Override
beforeConfiguration(ITestResult tr)1541     public void beforeConfiguration(ITestResult tr) {
1542     }
1543 
1544     @Override
onConfigurationFailure(ITestResult itr)1545     public void onConfigurationFailure(ITestResult itr) {
1546       m_failedConfigurations.addResult(itr, itr.getMethod());
1547     }
1548 
1549     @Override
onConfigurationSkip(ITestResult itr)1550     public void onConfigurationSkip(ITestResult itr) {
1551       m_skippedConfigurations.addResult(itr, itr.getMethod());
1552     }
1553 
1554     @Override
onConfigurationSuccess(ITestResult itr)1555     public void onConfigurationSuccess(ITestResult itr) {
1556       m_passedConfigurations.addResult(itr, itr.getMethod());
1557     }
1558   }
1559 
1560   @Deprecated
setMethodInterceptor(IMethodInterceptor methodInterceptor)1561   public void setMethodInterceptor(IMethodInterceptor methodInterceptor){
1562     m_methodInterceptors.add(methodInterceptor);
1563   }
1564 
addMethodInterceptor(IMethodInterceptor methodInterceptor)1565   public void addMethodInterceptor(IMethodInterceptor methodInterceptor){
1566     m_methodInterceptors.add(methodInterceptor);
1567   }
1568 
1569   @Override
getCurrentXmlTest()1570   public XmlTest getCurrentXmlTest() {
1571     return m_xmlTest;
1572   }
1573 
1574   private IAttributes m_attributes = new Attributes();
1575 
1576   @Override
getAttribute(String name)1577   public Object getAttribute(String name) {
1578     return m_attributes.getAttribute(name);
1579   }
1580 
1581   @Override
setAttribute(String name, Object value)1582   public void setAttribute(String name, Object value) {
1583     m_attributes.setAttribute(name, value);
1584   }
1585 
1586   @Override
getAttributeNames()1587   public Set<String> getAttributeNames() {
1588     return m_attributes.getAttributeNames();
1589   }
1590 
1591   @Override
removeAttribute(String name)1592   public Object removeAttribute(String name) {
1593     return m_attributes.removeAttribute(name);
1594   }
1595 
1596   private ListMultiMap<Class<? extends Module>, Module> m_guiceModules = Maps.newListMultiMap();
1597 
1598   @Override
getGuiceModules(Class<? extends Module> cls)1599   public List<Module> getGuiceModules(Class<? extends Module> cls) {
1600     List<Module> result = m_guiceModules.get(cls);
1601     return result;
1602   }
1603 
addGuiceModule(Class<? extends Module> cls, Module module)1604   private void addGuiceModule(Class<? extends Module> cls, Module module) {
1605     m_guiceModules.put(cls, module);
1606   }
1607 
1608   private Map<List<Module>, Injector> m_injectors = Maps.newHashMap();
1609 
1610   @Override
getInjector(List<Module> moduleInstances)1611   public Injector getInjector(List<Module> moduleInstances) {
1612     return m_injectors .get(moduleInstances);
1613   }
1614 
1615   @Override
getInjector(IClass iClass)1616   public Injector getInjector(IClass iClass) {
1617     Annotation annotation = AnnotationHelper.findAnnotationSuperClasses(Guice.class, iClass.getRealClass());
1618     if (annotation == null) return null;
1619     if (iClass instanceof TestClass) {
1620       iClass = ((TestClass)iClass).getIClass();
1621     }
1622     if (!(iClass instanceof ClassImpl)) return null;
1623     Injector parentInjector = ((ClassImpl)iClass).getParentInjector();
1624 
1625     Guice guice = (Guice) annotation;
1626     List<Module> moduleInstances = Lists.newArrayList(getModules(guice, parentInjector, iClass.getRealClass()));
1627 
1628     // Reuse the previous injector, if any
1629     Injector injector = getInjector(moduleInstances);
1630     if (injector == null) {
1631       injector = parentInjector.createChildInjector(moduleInstances);
1632       addInjector(moduleInstances, injector);
1633     }
1634     return injector;
1635   }
1636 
getModules(Guice guice, Injector parentInjector, Class<?> testClass)1637   private Module[] getModules(Guice guice, Injector parentInjector, Class<?> testClass) {
1638     List<Module> result = Lists.newArrayList();
1639     for (Class<? extends Module> moduleClass : guice.modules()) {
1640       List<Module> modules = getGuiceModules(moduleClass);
1641       if (modules != null && modules.size() > 0) {
1642         result.addAll(modules);
1643       } else {
1644         Module instance = parentInjector.getInstance(moduleClass);
1645         result.add(instance);
1646         addGuiceModule(moduleClass, instance);
1647       }
1648     }
1649     Class<? extends IModuleFactory> factory = guice.moduleFactory();
1650     if (factory != IModuleFactory.class) {
1651       IModuleFactory factoryInstance = parentInjector.getInstance(factory);
1652       Module moduleClass = factoryInstance.createModule(this, testClass);
1653       if (moduleClass != null) {
1654         result.add(moduleClass);
1655       }
1656     }
1657 
1658     return result.toArray(new Module[result.size()]);
1659   }
1660 
1661   @Override
addInjector(List<Module> moduleInstances, Injector injector)1662   public void addInjector(List<Module> moduleInstances, Injector injector) {
1663     m_injectors.put(moduleInstances, injector);
1664   }
1665 
1666 } // TestRunner
1667