1f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustpackage org.testng.internal;
2f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
3ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.lang.annotation.Annotation;
4ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.lang.reflect.InvocationTargetException;
5ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.lang.reflect.Method;
6ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.Collection;
7ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.Collections;
8ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.Iterator;
9ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.List;
10ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.Map;
11ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport java.util.Set;
1234ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust
13f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IClass;
14f325d9aa7a9505526a2ec933349aaf227ac23b43Julien Herrimport org.testng.IClassListener;
150bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beustimport org.testng.IConfigurable;
16ee8e37d41d7e14252ee649f13768022fee714afbCédric Beustimport org.testng.IConfigurationListener;
17eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beustimport org.testng.IConfigurationListener2;
18f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IHookable;
19398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beustimport org.testng.IInvokedMethod;
2038ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beustimport org.testng.IInvokedMethodListener;
21f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IRetryAnalyzer;
22f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestClass;
23f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestContext;
24f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestListener;
25f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestNGMethod;
26f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestResult;
27f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.Reporter;
28f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.SkipException;
29f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.SuiteRunState;
30f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.TestException;
31f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.TestNGException;
322d568355761a9632bf24a87984e241f8a079d724Cédric Beustimport org.testng.annotations.IConfigurationAnnotation;
33aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beustimport org.testng.annotations.NoInjection;
34ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beustimport org.testng.collections.Lists;
350f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.collections.Maps;
36e9a829e47a3f321807f9f3b6a15ec98ab6e22b98Julien Herrimport org.testng.collections.Sets;
37f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.InvokeMethodRunnable.TestNGRuntimeException;
389150cdf3bacb4715cee345cd153d4f0ab3dbd198nullinimport org.testng.internal.ParameterHolder.ParameterOrigin;
39f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.annotations.AnnotationHelper;
40f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.annotations.IAnnotationFinder;
4192d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermannimport org.testng.internal.invokers.InvokedMethodListenerInvoker;
4292d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermannimport org.testng.internal.invokers.InvokedMethodListenerMethod;
43f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.thread.ThreadExecutionException;
44f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.thread.ThreadUtil;
45f035a01bd8ac47425984d6b9e07a733f3abb3c37nullinimport org.testng.internal.thread.graph.IWorker;
46f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlClass;
47f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlSuite;
48f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlTest;
49f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
50ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport static org.testng.internal.invokers.InvokedMethodListenerMethod.AFTER_INVOCATION;
51ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport static org.testng.internal.invokers.InvokedMethodListenerMethod.BEFORE_INVOCATION;
52423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust
53f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust/**
54f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * This class is responsible for invoking methods:
55f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - test methods
56f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - configuration methods
57f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - possibly in a separate thread
58f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * and then for notifying the result listeners.
59f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust *
60f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
61f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
62f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust */
63f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustpublic class Invoker implements IInvoker {
6421dad3370294d6595fdddc3faf55792f60a913f1nullin  private final ITestContext m_testContext;
6521dad3370294d6595fdddc3faf55792f60a913f1nullin  private final ITestResultNotifier m_notifier;
6621dad3370294d6595fdddc3faf55792f60a913f1nullin  private final IAnnotationFinder m_annotationFinder;
6721dad3370294d6595fdddc3faf55792f60a913f1nullin  private final SuiteRunState m_suiteState;
68eddb4a9423c14fee808a30e92ad77a16e88b320enullin  private final boolean m_skipFailedInvocationCounts;
690643910fcfd637e5b30f0719a6085ae8f1829785Julien Herr  private final Collection<IInvokedMethodListener> m_invokedMethodListeners;
70eddb4a9423c14fee808a30e92ad77a16e88b320enullin  private final boolean m_continueOnFailedConfiguration;
71f325d9aa7a9505526a2ec933349aaf227ac23b43Julien Herr  private final List<IClassListener> m_classListeners;
7289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
7321dad3370294d6595fdddc3faf55792f60a913f1nullin  /** Group failures must be synced as the Invoker is accessed concurrently */
74423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  private Map<String, Boolean> m_beforegroupsFailures = Maps.newHashtable();
7589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
7621dad3370294d6595fdddc3faf55792f60a913f1nullin  /** Class failures must be synced as the Invoker is accessed concurrently */
77f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin  private Map<Class<?>, Set<Object>> m_classInvocationResults = Maps.newHashtable();
7889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
7962a82c6aa5725c9e9d600af5ee06a5852100208cnullin  /** Test methods whose configuration methods have failed. */
80f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin  private Map<ITestNGMethod, Set<Object>> m_methodInvocationResults = Maps.newHashtable();
813297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust  private IConfiguration m_configuration;
8289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
839d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  /** Predicate to filter methods */
849eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust  private static Predicate<ITestNGMethod, IClass> CAN_RUN_FROM_CLASS = new CanRunFromClassPredicate();
859d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  /** Predicate to filter methods */
869eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust  private static final Predicate<ITestNGMethod, IClass> SAME_CLASS = new SameClassNamePredicate();
879d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust
88423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  private void setClassInvocationFailure(Class<?> clazz, Object instance) {
89f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    Set<Object> instances = m_classInvocationResults.get( clazz );
90423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    if (instances == null) {
91f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      instances = Sets.newHashSet();
92423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      m_classInvocationResults.put(clazz, instances);
93423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    }
94423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    instances.add(instance);
9562a82c6aa5725c9e9d600af5ee06a5852100208cnullin  }
9689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
97423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  private void setMethodInvocationFailure(ITestNGMethod method, Object instance) {
98f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    Set<Object> instances = m_methodInvocationResults.get(method);
99423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    if (instances == null) {
100f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      instances = Sets.newHashSet();
101423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      m_methodInvocationResults.put(method, instances);
102423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    }
1032084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq    instances.add(getMethodInvocationToken(method, instance));
10462a82c6aa5725c9e9d600af5ee06a5852100208cnullin  }
105f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1063297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust  public Invoker(IConfiguration configuration,
1073297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust                 ITestContext testContext,
108f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                 ITestResultNotifier notifier,
109f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                 SuiteRunState state,
11038ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beust                 boolean skipFailedInvocationCounts,
111f325d9aa7a9505526a2ec933349aaf227ac23b43Julien Herr                 Collection<IInvokedMethodListener> invokedMethodListeners,
112f325d9aa7a9505526a2ec933349aaf227ac23b43Julien Herr                 List<IClassListener> classListeners) {
1133297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust    m_configuration = configuration;
114f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_testContext= testContext;
115f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_suiteState= state;
116f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_notifier= notifier;
1173297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust    m_annotationFinder= configuration.getAnnotationFinder();
1186cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust    m_skipFailedInvocationCounts = skipFailedInvocationCounts;
119398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust    m_invokedMethodListeners = invokedMethodListeners;
12062a82c6aa5725c9e9d600af5ee06a5852100208cnullin    m_continueOnFailedConfiguration = XmlSuite.CONTINUE.equals(testContext.getSuite().getXmlSuite().getConfigFailurePolicy());
121f325d9aa7a9505526a2ec933349aaf227ac23b43Julien Herr    m_classListeners = classListeners;
122f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
123f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
124f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
125f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Invoke configuration methods if they belong to the same TestClass passed
126f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * in parameter.. <p/>TODO: Calculate ahead of time which methods should be
127f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * invoked for each class. Might speed things up for users who invoke the
128f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * same test class with different parameters in the same suite run.
129f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   *
130f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * If instance is non-null, the configuration will be run on it.  If it is null,
131f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * the configuration methods will be run on all the instances retrieved
132f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * from the ITestClass.
133f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
134423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  @Override
135f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public void invokeConfigurations(IClass testClass,
136f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] allMethods,
137f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
138f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
139facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                                   Object[] parameterValues,
140f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Object instance)
141f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
142da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust    invokeConfigurations(testClass, null, allMethods, suite, params, parameterValues, instance,
143da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust        null);
144f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
145f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
146f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void invokeConfigurations(IClass testClass,
147f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod currentTestMethod,
148f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] allMethods,
149f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
150f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
151facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                                   Object[] parameterValues,
152da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                                   Object instance,
153da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                                   ITestResult testMethodResult)
154f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
155f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == allMethods) {
156161d9860588ad89389848d70eb0a2f6f0cb46d1bCédric Beust      log(5, "No configuration methods found");
157f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
158f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return;
159f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
160f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1619d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    ITestNGMethod[] methods= filterMethods(testClass, allMethods, SAME_CLASS);
162f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
163f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(ITestNGMethod tm : methods) {
164f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(null == testClass) {
165f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testClass= tm.getTestClass();
166f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
167f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      ITestResult testResult= new TestResult(testClass,
169f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             instance,
170f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             tm,
171f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             null,
172f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             System.currentTimeMillis(),
1736f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                             System.currentTimeMillis(),
1746f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                             m_testContext);
175f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1762d568355761a9632bf24a87984e241f8a079d724Cédric Beust      IConfigurationAnnotation configurationAnnotation= null;
177f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      try {
1786293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin        Object inst = tm.getInstance();
1796293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin        if (inst == null) {
1806293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin          inst = instance;
1810f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        }
1826293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin        Class<?> objectClass= inst.getClass();
183f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Method method= tm.getMethod();
184f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
185f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Only run the configuration if
186f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // - the test is enabled and
187f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // - the Configuration method belongs to the same class or a parent
188328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        configurationAnnotation = AnnotationHelper.findConfiguration(m_annotationFinder, method);
189328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        boolean alwaysRun= isAlwaysRun(configurationAnnotation);
190328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        if(MethodHelper.isEnabled(objectClass, m_annotationFinder) || alwaysRun) {
191f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
192e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust          if (MethodHelper.isEnabled(configurationAnnotation)) {
19389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
194423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust            if (!confInvocationPassed(tm, currentTestMethod, testClass, instance) && !alwaysRun) {
195423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust              handleConfigurationSkip(tm, testResult, configurationAnnotation, currentTestMethod, instance, suite);
196e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust              continue;
197e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            }
19889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
199e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            log(3, "Invoking " + Utils.detailedMethodName(tm, true));
20089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
201facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust            Object[] parameters = Parameters.createConfigurationParameters(tm.getMethod(),
202facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                params,
203facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                parameterValues,
204facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                currentTestMethod,
205facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                m_annotationFinder,
206facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                suite,
207da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                m_testContext,
208da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                testMethodResult);
209e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            testResult.setParameters(parameters);
21089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
2113cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin            Object newInstance = null != instance ? instance: inst;
21289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
213ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            runConfigurationListeners(testResult, true /* before */);
214ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust
2153cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin            invokeConfigurationMethod(newInstance, tm,
21600234ed4e19c38374d0bbd5bc2de771c90b16209Julien Herr              parameters, testResult);
21789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
218e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            // TODO: probably we should trigger the event for each instance???
219e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            testResult.setEndMillis(System.currentTimeMillis());
220ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            runConfigurationListeners(testResult, false /* after */);
221e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust          }
222e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust          else {
223e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            log(3,
224e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust                "Skipping "
225e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust                + Utils.detailedMethodName(tm, true)
226e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust                + " because it is not enabled");
227f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
228f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        } // if is enabled
229f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else {
230f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          log(3,
231f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              "Skipping "
232f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + Utils.detailedMethodName(tm, true)
233f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + " because "
234f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + objectClass.getName()
235f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + " is not enabled");
236f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
237f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
238f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      catch(InvocationTargetException ex) {
239423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, currentTestMethod, instance, suite);
240a3f78c5debcd03e7755f5ff2956a6f325e41d0b7Ryan Schmitt      } catch(Throwable ex) { // covers the non-wrapper exceptions
241423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, currentTestMethod, instance, suite);
242f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
243f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // for methods
244f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
24589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
246f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
24762a82c6aa5725c9e9d600af5ee06a5852100208cnullin   * Marks the current <code>TestResult</code> as skipped and invokes the listeners.
248f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
24989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void handleConfigurationSkip(ITestNGMethod tm,
25089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                       ITestResult testResult,
25189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                       IConfigurationAnnotation annotation,
25289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                       ITestNGMethod currentTestMethod,
253423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust                                       Object instance,
25462a82c6aa5725c9e9d600af5ee06a5852100208cnullin                                       XmlSuite suite) {
255423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    recordConfigurationInvocationFailed(tm, testResult.getTestClass(), annotation, currentTestMethod, instance, suite);
256f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    testResult.setStatus(ITestResult.SKIP);
257ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    runConfigurationListeners(testResult, false /* after */);
258f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
25989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
260f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
261f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Is the <code>IConfiguration</code> marked as alwaysRun.
262f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
2632d568355761a9632bf24a87984e241f8a079d724Cédric Beust  private boolean isAlwaysRun(IConfigurationAnnotation configurationAnnotation) {
264f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == configurationAnnotation) {
265f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return false;
266f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
26789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
268f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean alwaysRun= false;
269f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if ((configurationAnnotation.getAfterSuite()
270f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        || configurationAnnotation.getAfterTest()
271f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        || configurationAnnotation.getAfterTestClass()
272328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getAfterTestMethod()
273328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeTestMethod()
274328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeTestClass()
275328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeTest()
276328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeSuite())
277f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        && configurationAnnotation.getAlwaysRun())
278f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    {
279f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        alwaysRun= true;
280f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
28189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
282f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return alwaysRun;
283f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
28489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
285f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void handleConfigurationFailure(Throwable ite,
286f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          ITestNGMethod tm,
287f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          ITestResult testResult,
2882d568355761a9632bf24a87984e241f8a079d724Cédric Beust                                          IConfigurationAnnotation annotation,
28962a82c6aa5725c9e9d600af5ee06a5852100208cnullin                                          ITestNGMethod currentTestMethod,
290423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust                                          Object instance,
29189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                          XmlSuite suite)
292f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
293f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Throwable cause= ite.getCause() != null ? ite.getCause() : ite;
29489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
2956671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin    if(isSkipExceptionAndSkip(cause)) {
2966671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin      testResult.setThrowable(cause);
2976671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin      handleConfigurationSkip(tm, testResult, annotation, currentTestMethod, instance, suite);
2986671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin      return;
299f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
300161d9860588ad89389848d70eb0a2f6f0cb46d1bCédric Beust    Utils.log("", 3, "Failed to invoke configuration method "
301f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        + tm.getRealClass().getName() + "." + tm.getMethodName() + ":" + cause.getMessage());
302f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    handleException(cause, tm, testResult, 1);
303ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    runConfigurationListeners(testResult, false /* after */);
304f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
30589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    //
306f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If in TestNG mode, need to take a look at the annotation to figure out
307f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // what kind of @Configuration method we're dealing with
308f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
309f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (null != annotation) {
310423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      recordConfigurationInvocationFailed(tm, testResult.getTestClass(), annotation, currentTestMethod, instance, suite);
311f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
312f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
313f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
314f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
315f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return All the classes that belong to the same <test> tag as @param cls
316f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
317f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private XmlClass[] findClassesInSameTest(Class<?> cls, XmlSuite suite) {
3180f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust    Map<String, XmlClass> vResult= Maps.newHashMap();
319f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String className= cls.getName();
320f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(XmlTest test : suite.getTests()) {
321f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(XmlClass testClass : test.getXmlClasses()) {
322f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(testClass.getName().equals(className)) {
323f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
324f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // Found it, add all the classes in this test in the result
325f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          for(XmlClass thisClass : test.getXmlClasses()) {
326f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            vResult.put(thisClass.getName(), thisClass);
327f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
328f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // Note:  we need to iterate through the entire suite since the same
329f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // class might appear in several <test> tags
330f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
331f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
332f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
333f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
334f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    XmlClass[] result= vResult.values().toArray(new XmlClass[vResult.size()]);
335f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
336f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
337f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
338f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
339f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
340f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Record internally the failure of a Configuration, so that we can determine
341f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * later if @Test should be skipped.
342f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
34389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void recordConfigurationInvocationFailed(ITestNGMethod tm,
34489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                   IClass testClass,
34589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                   IConfigurationAnnotation annotation,
34689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                   ITestNGMethod currentTestMethod,
347423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust                                                   Object instance,
34862a82c6aa5725c9e9d600af5ee06a5852100208cnullin                                                   XmlSuite suite) {
34962a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // If beforeTestClass or afterTestClass failed, mark either the config method's
35062a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // entire class as failed, or the class under tests as failed, depending on
35162a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // the configuration failure policy
35262a82c6aa5725c9e9d600af5ee06a5852100208cnullin    if (annotation.getBeforeTestClass() || annotation.getAfterTestClass()) {
35362a82c6aa5725c9e9d600af5ee06a5852100208cnullin      // tm is the configuration method, and currentTestMethod is null for BeforeClass
35462a82c6aa5725c9e9d600af5ee06a5852100208cnullin      // methods, so we need testClass
35562a82c6aa5725c9e9d600af5ee06a5852100208cnullin      if (m_continueOnFailedConfiguration) {
356423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(testClass.getRealClass(), instance);
35762a82c6aa5725c9e9d600af5ee06a5852100208cnullin      } else {
358423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(tm.getRealClass(), instance);
35962a82c6aa5725c9e9d600af5ee06a5852100208cnullin      }
36062a82c6aa5725c9e9d600af5ee06a5852100208cnullin    }
36189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
36262a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // If before/afterTestMethod failed, mark either the config method's entire
36362a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // class as failed, or just the current test method as failed, depending on
36462a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // the configuration failure policy
36562a82c6aa5725c9e9d600af5ee06a5852100208cnullin    else if (annotation.getBeforeTestMethod() || annotation.getAfterTestMethod()) {
36662a82c6aa5725c9e9d600af5ee06a5852100208cnullin      if (m_continueOnFailedConfiguration) {
367423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setMethodInvocationFailure(currentTestMethod, instance);
36862a82c6aa5725c9e9d600af5ee06a5852100208cnullin      } else {
369423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(tm.getRealClass(), instance);
37062a82c6aa5725c9e9d600af5ee06a5852100208cnullin      }
371f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
372f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
373f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If beforeSuite or afterSuite failed, mark *all* the classes as failed
374f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // for configurations.  At this point, the entire Suite is screwed
375f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else if (annotation.getBeforeSuite() || annotation.getAfterSuite()) {
376f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_suiteState.failed();
377f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
378f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
379f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // beforeTest or afterTest:  mark all the classes in the same
380f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // <test> stanza as failed for configuration
381f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else if (annotation.getBeforeTest() || annotation.getAfterTest()) {
382423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      setClassInvocationFailure(tm.getRealClass(), instance);
383f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlClass[] classes= findClassesInSameTest(tm.getRealClass(), suite);
384f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(XmlClass xmlClass : classes) {
385423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(xmlClass.getSupportClass(), instance);
386f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
387f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
388f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] beforeGroups= annotation.getBeforeGroups();
389f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null != beforeGroups && beforeGroups.length > 0) {
390f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(String group: beforeGroups) {
391f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        m_beforegroupsFailures.put(group, Boolean.FALSE);
392f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
393f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
394f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
39589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
396f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
3972723c0384d932da07d978701ae8247ae5086ba38Cédric Beust   * @return true if this class or a parent class failed to initialize.
3982723c0384d932da07d978701ae8247ae5086ba38Cédric Beust   */
3992723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  private boolean classConfigurationFailed(Class<?> cls) {
4002723c0384d932da07d978701ae8247ae5086ba38Cédric Beust    for (Class<?> c : m_classInvocationResults.keySet()) {
4015472868e8d0434658827e3ebf479a37992012d46Julien Herr      if (c == cls || c.isAssignableFrom(cls)) {
4022723c0384d932da07d978701ae8247ae5086ba38Cédric Beust        return true;
4032723c0384d932da07d978701ae8247ae5086ba38Cédric Beust      }
4042723c0384d932da07d978701ae8247ae5086ba38Cédric Beust    }
4052723c0384d932da07d978701ae8247ae5086ba38Cédric Beust    return false;
4062723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  }
4072723c0384d932da07d978701ae8247ae5086ba38Cédric Beust
4082723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  /**
409f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if this class has successfully run all its @Configuration
410f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * method or false if at least one of these methods failed.
411f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
4122723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  private boolean confInvocationPassed(ITestNGMethod method, ITestNGMethod currentTestMethod,
4132723c0384d932da07d978701ae8247ae5086ba38Cédric Beust      IClass testClass, Object instance) {
414f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean result= true;
415f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
4169637d33cffacd41cf92ca042ff59188e3d09ddd1Julien Herr    Class<?> cls = testClass.getRealClass();
41762a82c6aa5725c9e9d600af5ee06a5852100208cnullin
418f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(m_suiteState.isFailed()) {
419f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      result= false;
420f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
421f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else {
4222723c0384d932da07d978701ae8247ae5086ba38Cédric Beust      if (classConfigurationFailed(cls)) {
4230f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        if (! m_continueOnFailedConfiguration) {
4242723c0384d932da07d978701ae8247ae5086ba38Cédric Beust          result = !classConfigurationFailed(cls);
4250f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        } else {
4260f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          result = !m_classInvocationResults.get(cls).contains(instance);
4270f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        }
428f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
42962a82c6aa5725c9e9d600af5ee06a5852100208cnullin      // if method is BeforeClass, currentTestMethod will be null
43089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      else if (m_continueOnFailedConfiguration &&
43189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              currentTestMethod != null &&
43262a82c6aa5725c9e9d600af5ee06a5852100208cnullin              m_methodInvocationResults.containsKey(currentTestMethod)) {
4332084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq        result = !m_methodInvocationResults.get(currentTestMethod).contains(getMethodInvocationToken(currentTestMethod, instance));
43462a82c6aa5725c9e9d600af5ee06a5852100208cnullin      }
435423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      else if (! m_continueOnFailedConfiguration) {
436f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        for(Class<?> clazz: m_classInvocationResults.keySet()) {
4371e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust//          if (clazz == cls) {
438f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          if(clazz.isAssignableFrom(cls)) {
439f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            result= false;
440f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            break;
441f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
442f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
443f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
444f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
445f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
446f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // check if there are failed @BeforeGroups
447f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] groups= method.getGroups();
448f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null != groups && groups.length > 0) {
449f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(String group: groups) {
450f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(m_beforegroupsFailures.containsKey(group)) {
451f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          result= false;
452f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
453f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
454f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
455f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
456f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
457f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
458f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
4592084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq   // Creates a token for tracking a unique invocation of a method on an instance.
4602084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq   // Is used when configFailurePolicy=continue.
4612084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq  private Object getMethodInvocationToken(ITestNGMethod method, Object instance) {
4622084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq    return String.format("%s+%d", instance.toString(), method.getCurrentInvocationCount());
4632084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq  }
4642084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq
465f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
466f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Effectively invokes a configuration method on all passed in instances.
467d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com   * TODO: Should change this method to be more like invokeMethod() so that we can
468d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com   * handle calls to {@code IInvokedMethodListener} better.
46989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   *
4703cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin   * @param targetInstance the instance to invoke the configuration method on
471f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param tm the configuration method
472f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param params the parameters needed for method invocation
473f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param testResult
474f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @throws InvocationTargetException
475f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @throws IllegalAccessException
476f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
4773cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin  private void invokeConfigurationMethod(Object targetInstance,
478f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         ITestNGMethod tm,
479f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         Object[] params,
480f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         ITestResult testResult)
48189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    throws InvocationTargetException, IllegalAccessException
482f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
483f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Mark this method with the current thread id
484f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    tm.setId(ThreadUtil.currentThreadInfo());
485f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
4863cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin    {
48792d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      InvokedMethod invokedMethod= new InvokedMethod(targetInstance,
488f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          tm,
489f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          params,
490234c85874acc0cd3360639949fbd566255ab31edCédric Beust                                          System.currentTimeMillis(),
491234c85874acc0cd3360639949fbd566255ab31edCédric Beust                                          testResult);
492f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
49392d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      runInvokedMethodListeners(BEFORE_INVOCATION, invokedMethod, testResult);
49492d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      m_notifier.addInvokedMethod(invokedMethod);
495f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      try {
496f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Reporter.setCurrentTestResult(testResult);
4970bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        Method method = tm.getMethod();
498e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust
499e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        //
5003cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin        // If this method is a IConfigurable, invoke its run() method
501e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        //
502e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        IConfigurable configurableInstance =
503e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust          IConfigurable.class.isAssignableFrom(tm.getMethod().getDeclaringClass()) ?
504e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust          (IConfigurable) targetInstance : m_configuration.getConfigurable();
505e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        if (configurableInstance != null) {
506b1c182d51b05a40ac5350e562503a94d024a7c80nullin          MethodInvocationHelper.invokeConfigurable(targetInstance, params, configurableInstance, method,
507e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust              testResult);
5080bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        }
5090bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        else {
5100bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust          //
511830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          // Not a IConfigurable, invoke directly
5120bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust          //
513830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          if (MethodHelper.calculateTimeOut(tm) <= 0) {
514b1c182d51b05a40ac5350e562503a94d024a7c80nullin            MethodInvocationHelper.invokeMethod(method, targetInstance, params);
515830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          }
516830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          else {
517b1c182d51b05a40ac5350e562503a94d024a7c80nullin            MethodInvocationHelper.invokeWithTimeout(tm, targetInstance, params, testResult);
518830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust            if (!testResult.isSuccess()) {
519830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust              // A time out happened
520830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust              throwConfigurationFailure(testResult, testResult.getThrowable());
521830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust              throw testResult.getThrowable();
522830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust            }
523830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          }
5240bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        }
525db66a3de4428040dd9f7e377a3b6835965c8b0cdCédric Beust      }
526a3f78c5debcd03e7755f5ff2956a6f325e41d0b7Ryan Schmitt      catch (InvocationTargetException | IllegalAccessException ex) {
5270bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust       throwConfigurationFailure(testResult, ex);
5280bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust       throw ex;
529a3f78c5debcd03e7755f5ff2956a6f325e41d0b7Ryan Schmitt      } catch (Throwable ex) {
5300bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        throwConfigurationFailure(testResult, ex);
5310bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        throw new TestNGException(ex);
5320bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust      }
5330bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust      finally {
534f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Reporter.setCurrentTestResult(testResult);
53592d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann        runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult);
536b1d4c2115043263424f47656ec336a5e5d9098f7Cédric Beust        Reporter.setCurrentTestResult(null);
53789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      }
538f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
539f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
540f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
5410bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust  private void throwConfigurationFailure(ITestResult testResult, Throwable ex)
5420bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust  {
5430bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust    testResult.setStatus(ITestResult.FAILURE);;
5440bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust    testResult.setThrowable(ex.getCause() == null ? ex : ex.getCause());
5450bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust  }
5460bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust
54792d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann  private void runInvokedMethodListeners(InvokedMethodListenerMethod listenerMethod, IInvokedMethod invokedMethod,
548398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust      ITestResult testResult)
549398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust  {
55092d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    if ( noListenersPresent() ) {
55192d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      return;
552398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust    }
55392d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann
55492d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    InvokedMethodListenerInvoker invoker = new InvokedMethodListenerInvoker(listenerMethod, testResult, m_testContext);
55592d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    for (IInvokedMethodListener currentListener : m_invokedMethodListeners) {
55692d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      invoker.invokeListener(currentListener, invokedMethod);
55792d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    }
55892d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann  }
55992d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann
56092d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann  private boolean noListenersPresent() {
56192d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    return (m_invokedMethodListeners == null) || (m_invokedMethodListeners.size() == 0);
562398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust  }
563398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust
564927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust  // pass both paramValues and paramIndex to be thread safe in case parallel=true + dataprovider.
5656293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin  private ITestResult invokeMethod(Object instance,
566f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   final ITestNGMethod tm,
567f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Object[] parameterValues,
568927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust                                   int parametersIndex,
569f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
570f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
571f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestClass testClass,
572f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] beforeMethods,
573f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] afterMethods,
5746b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                   ConfigurationGroupMethods groupMethods,
5756b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                   FailureContext failureContext) {
57694efdf8e6ac7332eadf8bfe5d1fe699caee5d051Cédric Beust    TestResult testResult = new TestResult();
57794efdf8e6ac7332eadf8bfe5d1fe699caee5d051Cédric Beust
578f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
579f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Invoke beforeGroups configurations
580f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
581f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    invokeBeforeGroupsConfigurations(testClass, tm, groupMethods, suite, params,
5823297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust        instance);
583f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
584f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
58545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // Invoke beforeMethods only if
58645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // - firstTimeOnly is not set
58745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // - firstTimeOnly is set, and we are reaching at the first invocationCount
588f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
58989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    invokeConfigurations(testClass, tm,
59045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      filterConfigurationMethods(tm, beforeMethods, true /* beforeMethods */),
591facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust      suite, params, parameterValues,
5923297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      instance, testResult);
59389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
594f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
595f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Create the ExtraOutput for this method
596f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
59738ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beust    InvokedMethod invokedMethod = null;
598f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    try {
5993297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      testResult.init(testClass, instance,
600f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 tm,
601f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 null,
602f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 System.currentTimeMillis(),
6036f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                 0,
6046f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                 m_testContext);
605f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setParameters(parameterValues);
606f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setHost(m_testContext.getHost());
607f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.STARTED);
608f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
6093297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      invokedMethod= new InvokedMethod(instance,
610f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          tm,
611f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          parameterValues,
612234c85874acc0cd3360639949fbd566255ab31edCédric Beust          System.currentTimeMillis(),
613234c85874acc0cd3360639949fbd566255ab31edCédric Beust          testResult);
614f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
615272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // Fix from ansgarkonermann
616272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // invokedMethod is used in the finally, which can be invoked if
617272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // any of the test listeners throws an exception, therefore,
618272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // invokedMethod must have a value before we get here
61959d29c5fddc09eb6dc132569b0f4c4026f033b1aAnsgar Konermann      runTestListeners(testResult);
62059d29c5fddc09eb6dc132569b0f4c4026f033b1aAnsgar Konermann
62192d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      runInvokedMethodListeners(BEFORE_INVOCATION, invokedMethod, testResult);
62238ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beust
623f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_notifier.addInvokedMethod(invokedMethod);
62489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
625dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      Method thisMethod = tm.getConstructorOrMethod().getMethod();
62689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
6273297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      if(confInvocationPassed(tm, tm, testClass, instance)) {
628dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        log(3, "Invoking " + tm.getRealClass().getName() + "." + tm.getMethodName());
629f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
6308e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        Reporter.setCurrentTestResult(testResult);
6318e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr
6328e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        // If this method is a IHookable, invoke its run() method
6338e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        IHookable hookableInstance =
6348e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr            IHookable.class.isAssignableFrom(tm.getRealClass()) ?
6353b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust            (IHookable) instance : m_configuration.getHookable();
6368e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr
6378e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        if (MethodHelper.calculateTimeOut(tm) <= 0) {
6383b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust          if (hookableInstance != null) {
6393b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust            MethodInvocationHelper.invokeHookable(instance,
6403b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust                parameterValues, hookableInstance, thisMethod, testResult);
6418e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr          } else {
6428e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr            // Not a IHookable, invoke directly
6433b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust            MethodInvocationHelper.invokeMethod(thisMethod, instance,
6443b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust                parameterValues);
645f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
6463b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust          testResult.setStatus(ITestResult.SUCCESS);
6478e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        } else {
648331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust          // Method with a timeout
6498e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr          MethodInvocationHelper.invokeWithTimeout(tm, instance, parameterValues, testResult, hookableInstance);
650f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
651f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
652f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
653f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setStatus(ITestResult.SKIP);
654f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
655f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
656f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(InvocationTargetException ite) {
657f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setThrowable(ite.getCause());
658d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com      testResult.setStatus(ITestResult.FAILURE);
659f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
660f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(ThreadExecutionException tee) { // wrapper for TestNGRuntimeException
661f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Throwable cause= tee.getCause();
662f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(TestNGRuntimeException.class.equals(cause.getClass())) {
663f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setThrowable(cause.getCause());
664f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
665f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
666f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setThrowable(cause);
667f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
668d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com      testResult.setStatus(ITestResult.FAILURE);
669f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
670f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(Throwable thr) { // covers the non-wrapper exceptions
671f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setThrowable(thr);
672d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com      testResult.setStatus(ITestResult.FAILURE);
673f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
674f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    finally {
675dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      // Set end time ASAP
676dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      testResult.setEndMillis(System.currentTimeMillis());
677dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin
678bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust      ExpectedExceptionsHolder expectedExceptionClasses
6793b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr          = new ExpectedExceptionsHolder(m_annotationFinder, tm, new RegexpExpectedExceptionsHolder(m_annotationFinder, tm));
680dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      List<ITestResult> results = Lists.<ITestResult>newArrayList(testResult);
68116d23357bbc58d4d394ac7a96b2bb8196cae6bf2Ryan Schmitt      handleInvocationResults(tm, results, expectedExceptionClasses, failureContext);
68289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
683dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      // If this method has a data provider and just failed, memorize the number
684dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      // at which it failed.
6851ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // Note: we're not exactly testing that this method has a data provider, just
6861ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // that it has parameters, so might have to revisit this if bugs get reported
6871ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // for the case where this method has parameters that don't come from a data
6881ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // provider
689dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      if (testResult.getThrowable() != null && parameterValues.length > 0) {
690927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust        tm.addFailedInvocationNumber(parametersIndex);
691dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      }
692dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust
693f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
694f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Increment the invocation count for this method
695f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
696f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      tm.incrementCurrentInvocationCount();
697f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
6987ba4f0edf349cd33491ea94c9ccf88ba9e1fa117Cédric Beust      // Run invokedMethodListeners after updating TestResult
6997ba4f0edf349cd33491ea94c9ccf88ba9e1fa117Cédric Beust      runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult);
7007ba4f0edf349cd33491ea94c9ccf88ba9e1fa117Cédric Beust      runTestListeners(testResult);
701bacea92cd4a97cc839df9533025400c343a4689fCédric Beust
702f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
70345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // Invoke afterMethods only if
70445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // - lastTimeOnly is not set
70545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // - lastTimeOnly is set, and we are reaching the last invocationCount
706f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
70789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      invokeConfigurations(testClass, tm,
70845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          filterConfigurationMethods(tm, afterMethods, false /* beforeMethods */),
709facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust          suite, params, parameterValues,
7103297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust          instance,
711da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust          testResult);
71289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
713f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
71445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // Invoke afterGroups configurations
715f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
716f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeAfterGroupsConfigurations(testClass, tm, groupMethods, suite,
7173297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust          params, instance);
7183b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust
7193b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust      // Reset the test result last. If we do this too early, Reporter.log()
7203b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust      // invocations from listeners will be discarded
7213b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust      Reporter.setCurrentTestResult(null);
722f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
72394efdf8e6ac7332eadf8bfe5d1fe699caee5d051Cédric Beust
724f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return testResult;
725f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
72689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
727dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin  void collectResults(ITestNGMethod testMethod, Collection<ITestResult> results) {
728dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    for (ITestResult result : results) {
72934ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      // Collect the results
730dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      final int status = result.getStatus();
73134ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      if(ITestResult.SUCCESS == status) {
732dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addPassedTest(testMethod, result);
73334ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
73434ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else if(ITestResult.SKIP == status) {
735dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addSkippedTest(testMethod, result);
73634ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
73734ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else if(ITestResult.FAILURE == status) {
738dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addFailedTest(testMethod, result);
73934ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
74034ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) {
741dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, result);
74234ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
74334ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else {
74434ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust        assert false : "UNKNOWN STATUS:" + status;
74534ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
74634ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust    }
74734ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust  }
74834ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust
749f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
75045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * The array of methods contains @BeforeMethods if isBefore if true, @AfterMethods
75145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * otherwise.  This function removes all the methods that should not be run at this
75245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * point because they are either firstTimeOnly or lastTimeOnly and we haven't reached
75345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * the current invocationCount yet
75445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   */
75545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  private ITestNGMethod[] filterConfigurationMethods(ITestNGMethod tm,
75645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      ITestNGMethod[] methods, boolean isBefore)
75745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  {
758ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestNGMethod> result = Lists.newArrayList();
75945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    for (ITestNGMethod m : methods) {
76045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      ConfigurationMethod cm = (ConfigurationMethod) m;
76145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      if (isBefore) {
76245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        if (! cm.isFirstTimeOnly() ||
76345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust            (cm.isFirstTimeOnly() && tm.getCurrentInvocationCount() == 0))
76445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        {
76545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          result.add(m);
76645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        }
76745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      }
76845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      else {
769d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        int current = tm.getCurrentInvocationCount();
770d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        boolean isLast = false;
7712fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // If we have parameters, set the boolean if we are about to run
7722fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // the last invocation
773d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        if (tm.getParameterInvocationCount() > 0) {
774ce11604bda708dbd2c42435e77027d5c360c9fa9Julien Herr          isLast = current == tm.getParameterInvocationCount() * tm.getTotalInvocationCount();
775d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        }
7762fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // If we have invocationCount > 1, set the boolean if we are about to
7772fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // run the last invocation
778ce11604bda708dbd2c42435e77027d5c360c9fa9Julien Herr        else if (tm.getTotalInvocationCount() > 1) {
779ce11604bda708dbd2c42435e77027d5c360c9fa9Julien Herr          isLast = current == tm.getTotalInvocationCount();
780d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        }
781d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        if (! cm.isLastTimeOnly() || (cm.isLastTimeOnly() && isLast)) {
78245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          result.add(m);
78345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        }
78445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      }
78545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    }
78645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust
78745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    return result.toArray(new ITestNGMethod[result.size()]);
78845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  }
78945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust
79045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  /**
791ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beust   * invokeTestMethods() eventually converge here to invoke a single @Test method.
792f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
793f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * This method is responsible for actually invoking the method. It decides if the invocation
794f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * must be done:
795f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <ul>
79689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * <li>through an <code>IHookable</code></li>
797f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <li>directly (through reflection)</li>
798f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <li>in a separate thread (in case it needs to timeout)
799f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * </ul>
80089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   *
801f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
802dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin   * This method is also responsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup
803f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * if it is the case for the passed in @Test method.
804f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
805dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin  protected ITestResult invokeTestMethod(Object instance,
806f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             final ITestNGMethod tm,
807f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Object[] parameterValues,
808927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust                                             int parametersIndex,
809f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             XmlSuite suite,
810f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Map<String, String> params,
811f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestClass testClass,
812f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestNGMethod[] beforeMethods,
813f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestNGMethod[] afterMethods,
8146b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                             ConfigurationGroupMethods groupMethods,
8156b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                             FailureContext failureContext)
816f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
817f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Mark this method with the current thread id
818f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    tm.setId(ThreadUtil.currentThreadInfo());
819f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
820dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    ITestResult result = invokeMethod(instance, tm, parameterValues, parametersIndex, suite, params,
8213b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                                      testClass, beforeMethods, afterMethods, groupMethods,
8223b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                                      failureContext);
823f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
824dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    return result;
825f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
826f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
827f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
828f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Filter all the beforeGroups methods and invoke only those that apply
829f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * to the current test method
830f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
83189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void invokeBeforeGroupsConfigurations(ITestClass testClass,
83289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                ITestNGMethod currentTestMethod,
83389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                ConfigurationGroupMethods groupMethods,
83489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                XmlSuite suite,
83589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                Map<String, String> params,
83689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                Object instance)
837f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
838f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    synchronized(groupMethods) {
839ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust      List<ITestNGMethod> filteredMethods = Lists.newArrayList();
840f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      String[] groups = currentTestMethod.getGroups();
841f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, List<ITestNGMethod>> beforeGroupMap = groupMethods.getBeforeGroupsMap();
84289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
843f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String group : groups) {
844f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        List<ITestNGMethod> methods = beforeGroupMap.get(group);
845f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (methods != null) {
846f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          filteredMethods.addAll(methods);
847f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
848f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
84989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
850f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] beforeMethodsArray = filteredMethods.toArray(new ITestNGMethod[filteredMethods.size()]);
851f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
852f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Invoke the right groups methods
853f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
854f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(beforeMethodsArray.length > 0) {
855f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // don't pass the IClass or the instance as the method may be external
856f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // the invocation must be similar to @BeforeTest/@BeforeSuite
85789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin        invokeConfigurations(null, beforeMethodsArray, suite, params,
858facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust            null, /* no parameter values */
859facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust            null);
860f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
86189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
862f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
863f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Remove them so they don't get run again
864f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
865f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      groupMethods.removeBeforeGroups(groups);
866f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
867f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
868f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
86989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void invokeAfterGroupsConfigurations(ITestClass testClass,
870f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               ITestNGMethod currentTestMethod,
871f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               ConfigurationGroupMethods groupMethods,
87289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                               XmlSuite suite,
87389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                               Map<String, String> params,
87489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                               Object instance)
875f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
876f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Skip this if the current method doesn't belong to any group
877f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // (only a method that belongs to a group can trigger the invocation
878f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // of afterGroups methods)
8790f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    if (currentTestMethod.getGroups().length == 0) {
8800f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      return;
8810f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    }
88289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
883f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // See if the currentMethod is the last method in any of the groups
884f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // it belongs to
8850f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust    Map<String, String> filteredGroups = Maps.newHashMap();
886f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] groups = currentTestMethod.getGroups();
887f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    synchronized(groupMethods) {
888f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String group : groups) {
889f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (groupMethods.isLastMethodForGroup(group, currentTestMethod)) {
890f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          filteredGroups.put(group, group);
891f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
892f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
89389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
8940f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if(filteredGroups.isEmpty()) {
8950f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        return;
8960f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
89789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
898f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // The list of afterMethods to run
8990f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust      Map<ITestNGMethod, ITestNGMethod> afterMethods = Maps.newHashMap();
90089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
901f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Now filteredGroups contains all the groups for which we need to run the afterGroups
902f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // method.  Find all the methods that correspond to these groups and invoke them.
903f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, List<ITestNGMethod>> map = groupMethods.getAfterGroupsMap();
904f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String g : filteredGroups.values()) {
905f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        List<ITestNGMethod> methods = map.get(g);
906f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Note:  should put them in a map if we want to make sure the same afterGroups
907f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // doesn't get run twice
908f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (methods != null) {
909f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          for (ITestNGMethod m : methods) {
910f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            afterMethods.put(m, m);
911f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
912f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
913f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
91489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
915f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Got our afterMethods, invoke them
916f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] afterMethodsArray = afterMethods.keySet().toArray(new ITestNGMethod[afterMethods.size()]);
917f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // don't pass the IClass or the instance as the method may be external
918f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // the invocation must be similar to @BeforeTest/@BeforeSuite
91989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      invokeConfigurations(null, afterMethodsArray, suite, params,
920facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust          null, /* no parameter values */
921facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust          null);
922f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
923f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Remove the groups so they don't get run again
92489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      groupMethods.removeAfterGroups(filteredGroups.keySet());
925f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
926f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
927f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
928f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private Object[] getParametersFromIndex(Iterator<Object[]> parametersValues, int index) {
929f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while (parametersValues.hasNext()) {
930f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object[] parameters = parametersValues.next();
931f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
932f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (index == 0) {
933f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        return parameters;
934f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
935f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      index--;
936f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
937f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return null;
938f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
93989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
9406293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin  int retryFailed(Object instance,
941f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           final ITestNGMethod tm,
942f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           XmlSuite suite,
943f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestClass testClass,
944f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestNGMethod[] beforeMethods,
945f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestNGMethod[] afterMethods,
946f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ConfigurationGroupMethods groupMethods,
947f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           List<ITestResult> result,
948f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           int failureCount,
949bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust                           ExpectedExceptionsHolder expectedExceptionHolder,
950f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestContext testContext,
951f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           Map<String, String> parameters,
952f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           int parametersIndex) {
9536b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    final FailureContext failure = new FailureContext();
9546b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    failure.count = failureCount;
95592206009b23ecbbf29e5a0d20f6b095a552afcb8Cédric Beust    do {
9566c40ac103c04fac38274dafc077d55df12e9d8d7Krishnan Mahadevan      failure.instances = Lists.newArrayList ();
9570f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust      Map<String, String> allParameters = Maps.newHashMap();
958f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      /**
959f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       * TODO: This recreates all the parameters every time when we only need
960f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       * one specific set. Should optimize it by only recreating the set needed.
961f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       */
962db04b1679d3367e54e61d7e6f8c225354e90081cCédric Beust      ParameterBag bag = createParameters(tm, parameters,
963c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin          allParameters, suite, testContext, null /* fedInstance */);
964c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust      Object[] parameterValues =
965c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust          getParametersFromIndex(bag.parameterHolder.parameters, parametersIndex);
966f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
9676b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin      result.add(invokeMethod(instance, tm, parameterValues, parametersIndex, suite,
9686b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin          allParameters, testClass, beforeMethods, afterMethods, groupMethods, failure));
969f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
9706b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    while (!failure.instances.isEmpty());
9716b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    return failure.count;
972f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
97389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
974db04b1679d3367e54e61d7e6f8c225354e90081cCédric Beust  private ParameterBag createParameters(ITestNGMethod testMethod,
975f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        Map<String, String> parameters,
976f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        Map<String, String> allParameterNames,
977f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        XmlSuite suite,
9788b9443a6ada20a1e9f3852b715f3e789a0f8d490Cédric Beust                                        ITestContext testContext,
979c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin                                        Object fedInstance)
9808778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust  {
9818778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    Object instance;
9828778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    if (fedInstance != null) {
9838778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust      instance = fedInstance;
9848778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    }
9858778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    else {
9867955b9d255852b83f9c96277dece4d6807cb69f5Cédric Beust      instance = testMethod.getInstance();
9878778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    }
98889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
989c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    ParameterBag bag = handleParameters(testMethod,
990c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin        instance, allParameterNames, parameters, null, suite, testContext, fedInstance, null);
991f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
992f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return bag;
993f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
99489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
995f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
996eddb4a9423c14fee808a30e92ad77a16e88b320enullin   * Invoke all the test methods. Note the plural: the method passed in
997f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * parameter might be invoked several times if the test class it belongs
998f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * to has more than one instance (i.e., if an @Factory method has been
999f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * declared somewhere that returns several instances of this TestClass).
1000f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * If no @Factory method was specified, testMethod will only be invoked
1001f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * once.
1002f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
1003f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Note that this method also takes care of invoking the beforeTestMethod
1004f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * and afterTestMethod, if any.
100589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   *
100689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * Note (alex): this method can be refactored to use a SingleTestMethodWorker that
100789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * directly invokes
10084dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin   * {@link #invokeTestMethod(Object, ITestNGMethod, Object[], int, XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods, FailureContext)}
1009f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * and this would simplify the implementation (see how DataTestMethodWorker is used)
1010f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1011423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  @Override
1012f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public List<ITestResult> invokeTestMethods(ITestNGMethod testMethod,
1013f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             XmlSuite suite,
1014e54cfbea931bc5370eeec8c03b92f6598577a5c4Cédric Beust                                             Map<String, String> testParameters,
1015f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ConfigurationGroupMethods groupMethods,
10166293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin                                             Object instance,
1017f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestContext testContext)
1018f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1019f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Potential bug here if the test method was declared on a parent class
102089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    assert null != testMethod.getTestClass()
1021dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        : "COULDN'T FIND TESTCLASS FOR " + testMethod.getRealClass();
102289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1023eddb4a9423c14fee808a30e92ad77a16e88b320enullin    if (!MethodHelper.isEnabled(testMethod.getMethod(), m_annotationFinder)) {
1024dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      // return if the method is not enabled. No need to do any more calculations
1025dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      return Collections.emptyList();
1026eddb4a9423c14fee808a30e92ad77a16e88b320enullin    }
1027eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1028a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    // By the time this testMethod to be invoked,
1029a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    // all dependencies should be already run or we need to skip this method,
1030a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    // so invocation count should not affect dependencies check
1031a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final String okToProceed = checkDependencies(testMethod, testContext.getAllTestMethods());
10324bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10334bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    if (okToProceed != null) {
10344bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      //
10354bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      // Not okToProceed. Test is being skipped
10364bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      //
1037a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin      ITestResult result = registerSkippedTestResult(testMethod, null, System.currentTimeMillis(),
1038a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin          new Throwable(okToProceed));
1039a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin      m_notifier.addSkippedTest(testMethod, result);
1040a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin      return Collections.singletonList(result);
10414bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    }
10424bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10434bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10444bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    final Map<String, String> parameters =
10454bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin        testMethod.findMethodParameters(testContext.getCurrentXmlTest());
10464bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10474bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    // For invocationCount > 1 and threadPoolSize > 1 run this method in its own pool thread.
10484bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    if (testMethod.getInvocationCount() > 1 && testMethod.getThreadPoolSize() > 1) {
10494bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      return invokePooledTestMethods(testMethod, suite, parameters, groupMethods, testContext);
10504bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    }
10514bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
1052331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust    long timeOutInvocationCount = testMethod.getInvocationTimeOut();
1053eddb4a9423c14fee808a30e92ad77a16e88b320enullin    //FIXME: Is this correct?
1054331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust    boolean onlyOne = testMethod.getThreadPoolSize() > 1 ||
1055331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust      timeOutInvocationCount > 0;
105689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1057331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust    int invocationCount = onlyOne ? 1 : testMethod.getInvocationCount();
1058f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
105989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    ExpectedExceptionsHolder expectedExceptionHolder =
10603b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr        new ExpectedExceptionsHolder(m_annotationFinder, testMethod,
10613b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                                     new RegexpExpectedExceptionsHolder(m_annotationFinder, testMethod));
1062a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final ITestClass testClass= testMethod.getTestClass();
1063a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final List<ITestResult> result = Lists.newArrayList();
10646b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    final FailureContext failure = new FailureContext();
1065a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods(), CAN_RUN_FROM_CLASS);
1066a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods(), CAN_RUN_FROM_CLASS);
1067f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while(invocationCount-- > 0) {
10684bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      if(false) {
10694bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin        // Prevent code formatting
1070eddb4a9423c14fee808a30e92ad77a16e88b320enullin      }
1071eddb4a9423c14fee808a30e92ad77a16e88b320enullin      //
1072eddb4a9423c14fee808a30e92ad77a16e88b320enullin      // No threads, regular invocation
1073eddb4a9423c14fee808a30e92ad77a16e88b320enullin      //
1074eddb4a9423c14fee808a30e92ad77a16e88b320enullin      else {
1075a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin        // Used in catch statement
1076a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin        long start = System.currentTimeMillis();
1077eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1078eddb4a9423c14fee808a30e92ad77a16e88b320enullin        Map<String, String> allParameterNames = Maps.newHashMap();
1079db04b1679d3367e54e61d7e6f8c225354e90081cCédric Beust        ParameterBag bag = createParameters(testMethod,
1080c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin            parameters, allParameterNames, suite, testContext, instance);
1081eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1082eddb4a9423c14fee808a30e92ad77a16e88b320enullin        if (bag.hasErrors()) {
10834dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          final ITestResult tr = bag.errorResult;
10844dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          tr.setStatus(ITestResult.SKIP);
10854dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          runTestListeners(tr);
10864dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          m_notifier.addSkippedTest(testMethod, tr);
1087061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust          result.add(tr);
1088eddb4a9423c14fee808a30e92ad77a16e88b320enullin          continue;
1089eddb4a9423c14fee808a30e92ad77a16e88b320enullin        }
1090eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1091eddb4a9423c14fee808a30e92ad77a16e88b320enullin        Iterator<Object[]> allParameterValues = bag.parameterHolder.parameters;
1092eddb4a9423c14fee808a30e92ad77a16e88b320enullin        int parametersIndex = 0;
1093eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1094eddb4a9423c14fee808a30e92ad77a16e88b320enullin        try {
1095eddb4a9423c14fee808a30e92ad77a16e88b320enullin          List<TestMethodWithDataProviderMethodWorker> workers = Lists.newArrayList();
1096eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1097eddb4a9423c14fee808a30e92ad77a16e88b320enullin          if (bag.parameterHolder.origin == ParameterOrigin.ORIGIN_DATA_PROVIDER &&
1098eddb4a9423c14fee808a30e92ad77a16e88b320enullin              bag.parameterHolder.dataProviderHolder.annotation.isParallel()) {
1099eddb4a9423c14fee808a30e92ad77a16e88b320enullin            while (allParameterValues.hasNext()) {
1100eddb4a9423c14fee808a30e92ad77a16e88b320enullin              Object[] parameterValues = injectParameters(allParameterValues.next(),
1101eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  testMethod.getMethod(), testContext, null /* test result */);
1102eddb4a9423c14fee808a30e92ad77a16e88b320enullin              TestMethodWithDataProviderMethodWorker w =
1103eddb4a9423c14fee808a30e92ad77a16e88b320enullin                new TestMethodWithDataProviderMethodWorker(this,
1104eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    testMethod, parametersIndex,
11056293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin                    parameterValues, instance, suite, parameters, testClass,
1106eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    beforeMethods, afterMethods, groupMethods,
1107eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    expectedExceptionHolder, testContext, m_skipFailedInvocationCounts,
11086b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    invocationCount, failure.count, m_notifier);
1109eddb4a9423c14fee808a30e92ad77a16e88b320enullin              workers.add(w);
1110eddb4a9423c14fee808a30e92ad77a16e88b320enullin              // testng387: increment the param index in the bag.
1111eddb4a9423c14fee808a30e92ad77a16e88b320enullin              parametersIndex++;
1112eddb4a9423c14fee808a30e92ad77a16e88b320enullin            }
11139eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            PoolService<List<ITestResult>> ps =
111410c223b7aa6bf34778079bb5ee1a494c83cd1239Ryan Schmitt                    new PoolService<>(suite.getDataProviderThreadCount());
11159eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            List<List<ITestResult>> r = ps.submitTasksAndWait(workers);
11169eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            for (List<ITestResult> l2 : r) {
11179eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust              result.addAll(l2);
11189eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            }
1119eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1120eddb4a9423c14fee808a30e92ad77a16e88b320enullin          } else {
1121eddb4a9423c14fee808a30e92ad77a16e88b320enullin            while (allParameterValues.hasNext()) {
1122eddb4a9423c14fee808a30e92ad77a16e88b320enullin              Object[] parameterValues = injectParameters(allParameterValues.next(),
1123eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  testMethod.getMethod(), testContext, null /* test result */);
1124eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1125eddb4a9423c14fee808a30e92ad77a16e88b320enullin              List<ITestResult> tmpResults = Lists.newArrayList();
1126eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1127eddb4a9423c14fee808a30e92ad77a16e88b320enullin              try {
1128dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                tmpResults.add(invokeTestMethod(instance,
1129dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    testMethod,
1130dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    parameterValues,
1131dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    parametersIndex,
1132dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    suite,
1133dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    parameters,
1134dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    testClass,
1135dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    beforeMethods,
1136dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    afterMethods,
11376b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    groupMethods, failure));
1138eddb4a9423c14fee808a30e92ad77a16e88b320enullin              }
1139eddb4a9423c14fee808a30e92ad77a16e88b320enullin              finally {
11406b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                if (failure.instances.isEmpty()) {
1141eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  result.addAll(tmpResults);
1142eddb4a9423c14fee808a30e92ad77a16e88b320enullin                } else {
11436b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                  for (Object failedInstance : failure.instances) {
1144eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    List<ITestResult> retryResults = Lists.newArrayList();
1145eddb4a9423c14fee808a30e92ad77a16e88b320enullin
11466b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    failure.count = retryFailed(
11476b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                            failedInstance, testMethod, suite, testClass, beforeMethods,
1148eddb4a9423c14fee808a30e92ad77a16e88b320enullin                     afterMethods, groupMethods, retryResults,
11496b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                     failure.count, expectedExceptionHolder,
1150eddb4a9423c14fee808a30e92ad77a16e88b320enullin                     testContext, parameters, parametersIndex);
1151eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  result.addAll(retryResults);
1152eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  }
1153eddb4a9423c14fee808a30e92ad77a16e88b320enullin                }
1154eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1155eddb4a9423c14fee808a30e92ad77a16e88b320enullin                //
1156eddb4a9423c14fee808a30e92ad77a16e88b320enullin                // If we have a failure, skip all the
1157eddb4a9423c14fee808a30e92ad77a16e88b320enullin                // other invocationCounts
1158eddb4a9423c14fee808a30e92ad77a16e88b320enullin                //
11596b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                if (failure.count > 0
1160eddb4a9423c14fee808a30e92ad77a16e88b320enullin                      && (m_skipFailedInvocationCounts
1161eddb4a9423c14fee808a30e92ad77a16e88b320enullin                            || testMethod.skipFailedInvocations())) {
1162eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  while (invocationCount-- > 0) {
11636b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    result.add(registerSkippedTestResult(testMethod, instance, System.currentTimeMillis(), null));
1164eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  }
1165eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  break;
1166eddb4a9423c14fee808a30e92ad77a16e88b320enullin                }
1167eddb4a9423c14fee808a30e92ad77a16e88b320enullin              }// end finally
1168eddb4a9423c14fee808a30e92ad77a16e88b320enullin              parametersIndex++;
1169eddb4a9423c14fee808a30e92ad77a16e88b320enullin            }
1170eddb4a9423c14fee808a30e92ad77a16e88b320enullin          }
1171eddb4a9423c14fee808a30e92ad77a16e88b320enullin        }
1172eddb4a9423c14fee808a30e92ad77a16e88b320enullin        catch (Throwable cause) {
1173eddb4a9423c14fee808a30e92ad77a16e88b320enullin          ITestResult r =
1174eddb4a9423c14fee808a30e92ad77a16e88b320enullin              new TestResult(testMethod.getTestClass(),
11756293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin                instance,
1176eddb4a9423c14fee808a30e92ad77a16e88b320enullin                testMethod,
1177eddb4a9423c14fee808a30e92ad77a16e88b320enullin                cause,
1178eddb4a9423c14fee808a30e92ad77a16e88b320enullin                start,
11796f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                System.currentTimeMillis(),
11806f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                m_testContext);
1181eddb4a9423c14fee808a30e92ad77a16e88b320enullin            r.setStatus(TestResult.FAILURE);
1182eddb4a9423c14fee808a30e92ad77a16e88b320enullin            result.add(r);
1183eddb4a9423c14fee808a30e92ad77a16e88b320enullin            runTestListeners(r);
1184eddb4a9423c14fee808a30e92ad77a16e88b320enullin            m_notifier.addFailedTest(testMethod, r);
1185eddb4a9423c14fee808a30e92ad77a16e88b320enullin        } // catch
1186f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1187f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
118889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1189f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
119089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1191f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  } // invokeTestMethod
1192f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1193252c45802df7624a4fafbce810e05d22048f437bCédric Beust  private ITestResult registerSkippedTestResult(ITestNGMethod testMethod, Object instance,
1194fe08327fabe1654f4f509edcf28c3296ad054fc5Cédric Beust      long start, Throwable throwable) {
119589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    ITestResult result =
1196252c45802df7624a4fafbce810e05d22048f437bCédric Beust      new TestResult(testMethod.getTestClass(),
1197252c45802df7624a4fafbce810e05d22048f437bCédric Beust        instance,
1198252c45802df7624a4fafbce810e05d22048f437bCédric Beust        testMethod,
1199fe08327fabe1654f4f509edcf28c3296ad054fc5Cédric Beust        throwable,
1200252c45802df7624a4fafbce810e05d22048f437bCédric Beust        start,
12016f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen        System.currentTimeMillis(),
12026f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen        m_testContext);
1203252c45802df7624a4fafbce810e05d22048f437bCédric Beust    result.setStatus(TestResult.SKIP);
1204252c45802df7624a4fafbce810e05d22048f437bCédric Beust    runTestListeners(result);
1205252c45802df7624a4fafbce810e05d22048f437bCédric Beust
1206252c45802df7624a4fafbce810e05d22048f437bCédric Beust    return result;
1207252c45802df7624a4fafbce810e05d22048f437bCédric Beust  }
1208252c45802df7624a4fafbce810e05d22048f437bCédric Beust
120928e899a6c1620c8d07cb04a92f96658550e4af16nullin  /**
121028e899a6c1620c8d07cb04a92f96658550e4af16nullin   * Gets an array of parameter values returned by data provider or the ones that
121128e899a6c1620c8d07cb04a92f96658550e4af16nullin   * are injected based on parameter type. The method also checks for {@code NoInjection}
121228e899a6c1620c8d07cb04a92f96658550e4af16nullin   * annotation
121328e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param parameterValues parameter values from a data provider
121428e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param method method to be invoked
121528e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param context test context
121628e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param testResult test result
121728e899a6c1620c8d07cb04a92f96658550e4af16nullin   */
12181e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust  private Object[] injectParameters(Object[] parameterValues, Method method,
121928e899a6c1620c8d07cb04a92f96658550e4af16nullin      ITestContext context, ITestResult testResult)
122028e899a6c1620c8d07cb04a92f96658550e4af16nullin    throws TestNGException {
12211e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    List<Object> vResult = Lists.newArrayList();
12221e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    int i = 0;
122328e899a6c1620c8d07cb04a92f96658550e4af16nullin    int numValues = parameterValues.length;
122428e899a6c1620c8d07cb04a92f96658550e4af16nullin    int numParams = method.getParameterTypes().length;
122528e899a6c1620c8d07cb04a92f96658550e4af16nullin
12268211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust    if (numValues > numParams && ! method.isVarArgs()) {
12278211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust      throw new TestNGException("The data provider is trying to pass " + numValues
12288211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          + " parameters but the method "
12298211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          + method.getDeclaringClass().getName() + "#" + method.getName()
12308211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          + " takes " + numParams);
123128e899a6c1620c8d07cb04a92f96658550e4af16nullin    }
123228e899a6c1620c8d07cb04a92f96658550e4af16nullin
123328e899a6c1620c8d07cb04a92f96658550e4af16nullin    // beyond this, numValues <= numParams
12341e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    for (Class<?> cls : method.getParameterTypes()) {
1235aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      Annotation[] annotations = method.getParameterAnnotations()[i];
1236aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      boolean noInjection = false;
1237aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      for (Annotation a : annotations) {
1238aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust        if (a instanceof NoInjection) {
1239aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust          noInjection = true;
1240aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust          break;
1241aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust        }
1242aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      }
12431e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust      Object injected = Parameters.getInjectedParameter(cls, method, context, testResult);
1244aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      if (injected != null && ! noInjection) {
12451e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust        vResult.add(injected);
12461e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust      } else {
124728e899a6c1620c8d07cb04a92f96658550e4af16nullin        try {
1248e7405399f36ed7b9383424f5175980fe2698a403Cédric Beust          if (method.isVarArgs()) vResult.add(parameterValues);
1249e7405399f36ed7b9383424f5175980fe2698a403Cédric Beust          else vResult.add(parameterValues[i++]);
125028e899a6c1620c8d07cb04a92f96658550e4af16nullin        } catch (ArrayIndexOutOfBoundsException ex) {
12518211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          throw new TestNGException("The data provider is trying to pass " + numValues
12528211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + " parameters but the method "
12538211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + method.getDeclaringClass().getName() + "#" + method.getName()
12548211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + " takes " + numParams
12558211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + " and TestNG is unable in inject a suitable object", ex);
125628e899a6c1620c8d07cb04a92f96658550e4af16nullin        }
12571e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust      }
12581e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    }
12591e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    return vResult.toArray(new Object[vResult.size()]);
12601e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust  }
12611e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust
1262f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ParameterBag handleParameters(ITestNGMethod testMethod,
1263f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object instance,
1264f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> allParameterNames,
1265f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> parameters,
1266facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust      Object[] parameterValues,
1267f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlSuite suite,
12688b9443a6ada20a1e9f3852b715f3e789a0f8d490Cédric Beust      ITestContext testContext,
1269da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust      Object fedInstance,
1270da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust      ITestResult testResult)
1271f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1272f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    try {
1273c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust      return new ParameterBag(
1274c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust          Parameters.handleParameters(testMethod,
127589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin            allParameterNames,
127689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin            instance,
127766aec6c16d8782f01933c0b45e1c5b3976e04dd6Cédric Beust            new Parameters.MethodParameters(parameters,
127866aec6c16d8782f01933c0b45e1c5b3976e04dd6Cédric Beust                testMethod.findMethodParameters(testContext.getCurrentXmlTest()),
127966aec6c16d8782f01933c0b45e1c5b3976e04dd6Cédric Beust                parameterValues,
128089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                testMethod.getMethod(), testContext, testResult),
128189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin            suite,
1282c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust            m_annotationFinder,
1283c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin            fedInstance));
1284f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1285061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust//    catch(TestNGException ex) {
1286061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust//      throw ex;
1287061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust//    }
1288f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(Throwable cause) {
1289c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      return new ParameterBag(
1290f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          new TestResult(
129189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              testMethod.getTestClass(),
129289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              instance,
129389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              testMethod,
129489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              cause,
1295f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              System.currentTimeMillis(),
12966f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen              System.currentTimeMillis(),
12976f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen              m_testContext));
1298f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1299f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
130089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1301f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
130289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * Invokes a method that has a specified threadPoolSize.
1303f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
130489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private List<ITestResult> invokePooledTestMethods(ITestNGMethod testMethod,
130589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                    XmlSuite suite,
130689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                    Map<String, String> parameters,
1307f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                    ConfigurationGroupMethods groupMethods,
130889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                    ITestContext testContext)
1309f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1310f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1311f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Create the workers
1312f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1313f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    List<IWorker<ITestNGMethod>> workers = Lists.newArrayList();
131489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
13159d65d102f64e4fe2e629de8e87c8b92379a9349eCédric Beust    // Create one worker per invocationCount
1316f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (int i = 0; i < testMethod.getInvocationCount(); i++) {
1317f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // we use clones for reporting purposes
1318f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod clonedMethod= testMethod.clone();
1319f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      clonedMethod.setInvocationCount(1);
1320f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      clonedMethod.setThreadPoolSize(1);
1321f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1322eb2b9ac857aad415986677a51513d47e91eb7c8dCédric Beust      MethodInstance mi = new MethodInstance(clonedMethod);
1323f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      workers.add(new SingleTestMethodWorker(this,
1324f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          mi,
132589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin          suite,
1326f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          parameters,
1327f325d9aa7a9505526a2ec933349aaf227ac23b43Julien Herr          testContext,
1328f325d9aa7a9505526a2ec933349aaf227ac23b43Julien Herr          m_classListeners));
1329f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1330f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
13313b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr    return runWorkers(testMethod, workers, testMethod.getThreadPoolSize(), groupMethods, suite,
13323b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                      parameters);
1333f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
133489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
13356b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  static class FailureContext {
13366b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    int count = 0;
13376b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    List<Object> instances = Lists.newArrayList();
13386b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  }
13396b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin
13406b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  void handleInvocationResults(ITestNGMethod testMethod,
13416b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                               List<ITestResult> result,
13426b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                               ExpectedExceptionsHolder expectedExceptionsHolder,
13436b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                               FailureContext failure)
13446216d78ae0757b7d57aa6e94cc041447d610724dCédric Beust  {
1345f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1346f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Go through all the results and create a TestResult for each of them
1347f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1348ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestResult> resultsToRetry = Lists.newArrayList();
1349f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
13506293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin    for (ITestResult testResult : result) {
1351f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Throwable ite= testResult.getThrowable();
1352f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      int status= testResult.getStatus();
1353f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
13546b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin      boolean handled = false;
13556b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin
1356f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Exception thrown?
13574c02d89d66fe0319dd20083e705addd6b5f3e8cdCédric Beust      if (ite != null) {
1358f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1359f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        //  Invocation caused an exception, see if the method was annotated with @ExpectedException
1360f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr        if (expectedExceptionsHolder != null) {
1361cda168c708e5d841b5cd0138b93d45f75b22178eJulien Herr          if (expectedExceptionsHolder.isExpectedException(ite)) {
1362bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust            testResult.setStatus(ITestResult.SUCCESS);
1363cda168c708e5d841b5cd0138b93d45f75b22178eJulien Herr            status = ITestResult.SUCCESS;
1364cda168c708e5d841b5cd0138b93d45f75b22178eJulien Herr          } else {
1365f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr            if (isSkipExceptionAndSkip(ite)){
1366f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr              status = ITestResult.SKIP;
1367f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr            } else {
1368f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr              testResult.setThrowable(expectedExceptionsHolder.wrongException(ite));
1369f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr              status = ITestResult.FAILURE;
1370f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr            }
1371bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust          }
13722343cba1dccc30a50322215da78f14179e2a0271Cédric Beust        } else {
13736b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin          handleException(ite, testMethod, testResult, failure.count++);
13746b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin          handled = true;
1375e919e3dd5edc2dd81296a00446211092f25f54f7Vladislav Rassokhin          status = testResult.getStatus();
1376f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1377f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1378f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1379f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // No exception thrown, make sure we weren't expecting one
1380bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust      else if(status != ITestResult.SKIP && expectedExceptionsHolder != null) {
1381c50c280b710dc2a33f76f24382242d07e74a268aJulien Herr        TestException exception = expectedExceptionsHolder.noException(testMethod);
1382c55504f189ef27cef6a662084c9353daec31afc9Julien Herr        if (exception != null) {
1383c55504f189ef27cef6a662084c9353daec31afc9Julien Herr          testResult.setThrowable(exception);
1384f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          status= ITestResult.FAILURE;
1385f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1386f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1387f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1388d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      IRetryAnalyzer retryAnalyzer = testMethod.getRetryAnalyzer();
1389d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      boolean willRetry = retryAnalyzer != null && status == ITestResult.FAILURE && failure.instances != null && retryAnalyzer.retry(testResult);
1390f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1391d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      if (willRetry) {
1392d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        resultsToRetry.add(testResult);
139316d23357bbc58d4d394ac7a96b2bb8196cae6bf2Ryan Schmitt        failure.count++;
1394d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        failure.instances.add(testResult.getInstance());
1395d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        testResult.setStatus(ITestResult.SKIP);
1396d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      } else {
1397d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        testResult.setStatus(status);
1398d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        if (status == ITestResult.FAILURE && !handled) {
1399d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt          handleException(ite, testMethod, testResult, failure.count++);
1400f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
140189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      }
140216d23357bbc58d4d394ac7a96b2bb8196cae6bf2Ryan Schmitt      collectResults(testMethod, Collections.singleton(testResult));
1403f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // for results
140489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
14056b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    removeResultsToRetryFromResult(resultsToRetry, result, failure);
1406f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
140789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
14086671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin  private boolean isSkipExceptionAndSkip(Throwable ite) {
14096671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin    return SkipException.class.isAssignableFrom(ite.getClass()) && ((SkipException) ite).isSkip();
14106671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin  }
1411c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin
14126b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  private void removeResultsToRetryFromResult(List<ITestResult> resultsToRetry,
14136b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                              List<ITestResult> result, FailureContext failure) {
1414f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (resultsToRetry != null) {
1415f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (ITestResult res : resultsToRetry) {
1416f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        result.remove(res);
14176b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin        failure.count--;
1418f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1419f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1420f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
142189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1422f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1423f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * To reduce thread contention and also to correctly handle thread-confinement
1424f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * this method invokes the @BeforeGroups and @AfterGroups corresponding to the current @Test method.
1425f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
142689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private List<ITestResult> runWorkers(ITestNGMethod testMethod,
1427c4cadec5fb52419e211120aa93b6118a4ab756ecCédric Beust      List<IWorker<ITestNGMethod>> workers,
142889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      int threadPoolSize,
142989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      ConfigurationGroupMethods groupMethods,
143089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      XmlSuite suite,
1431f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> parameters)
1432f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
143389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    // Invoke @BeforeGroups on the original method (reduce thread contention,
1434c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust    // and also solve thread confinement)
1435f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ITestClass testClass= testMethod.getTestClass();
1436f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Object[] instances = testClass.getInstances(true);
1437f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(Object instance: instances) {
1438f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeBeforeGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance);
1439f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
144089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
144189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1442f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    long maxTimeOut= -1; // 10 seconds
1443f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1444f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    for(IWorker<ITestNGMethod> tmw : workers) {
1445f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      long mt= tmw.getTimeOut();
1446f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(mt > maxTimeOut) {
1447f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        maxTimeOut= mt;
1448f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1449f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
145089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1451f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ThreadUtil.execute(workers, threadPoolSize, maxTimeOut, true);
1452f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1453f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1454f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Collect all the TestResults
1455f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1456ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestResult> result = Lists.newArrayList();
1457f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    for (IWorker<ITestNGMethod> tmw : workers) {
1458f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      if (tmw instanceof TestMethodWorker) {
1459f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin        result.addAll(((TestMethodWorker)tmw).getTestResults());
1460f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      }
1461f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
146289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1463f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(Object instance: instances) {
1464f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeAfterGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance);
1465f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
146689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1467f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1468f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1469f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1470f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1471e934f66fb4fb247ebf5fec45770bc6820fbba29anullin   * Checks to see of the test method has certain dependencies that prevents
1472e934f66fb4fb247ebf5fec45770bc6820fbba29anullin   * TestNG from executing it
1473e934f66fb4fb247ebf5fec45770bc6820fbba29anullin   * @param testMethod test method being checked for
1474627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin   * @return error message or null if dependencies have been run successfully
1475f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1476627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin  private String checkDependencies(ITestNGMethod testMethod,
1477627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin                                   ITestNGMethod[] allTestMethods)
1478f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1479e934f66fb4fb247ebf5fec45770bc6820fbba29anullin    // If this method is marked alwaysRun, no need to check for its dependencies
1480f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (testMethod.isAlwaysRun()) {
1481627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      return null;
1482f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
148389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1484f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Any missing group?
14850f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    if (testMethod.getMissingGroup() != null
1486627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        && !testMethod.ignoreMissingDependencies()) {
1487627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      return "Method " + testMethod + " depends on nonexistent group \"" + testMethod.getMissingGroup() + "\"";
1488f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1489f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1490f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If this method depends on groups, collect all the methods that
1491f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // belong to these groups and make sure they have been run successfully
1492627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    final String[] groups = testMethod.getGroupsDependedUpon();
1493627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    if (null != groups && groups.length > 0) {
1494f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Get all the methods that belong to the group depended upon
1495627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      for (String element : groups) {
149689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin        ITestNGMethod[] methods =
1497627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin            MethodGroupsHelper.findMethodsThatBelongToGroup(testMethod,
1498627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin                m_testContext.getAllTestMethods(),
1499627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin                element);
1500627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        if (methods.length == 0 && !testMethod.ignoreMissingDependencies()) {
1501627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          // Group is missing
1502627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          return "Method " + testMethod + " depends on nonexistent group \"" + element + "\"";
1503627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        }
1504627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        if (!haveBeenRunSuccessfully(testMethod, methods)) {
1505627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          return "Method " + testMethod +
1506627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin              " depends on not successfully finished methods in group \"" + element + "\"";
1507627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        }
1508f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1509f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // depends on groups
1510f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1511f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If this method depends on other methods, make sure all these other
1512f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // methods have been run successfully
1513627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    if (dependsOnMethods(testMethod)) {
151489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      ITestNGMethod[] methods =
1515627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          MethodHelper.findDependedUponMethods(testMethod, allTestMethods);
1516f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1517627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      if (!haveBeenRunSuccessfully(testMethod, methods)) {
1518627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        return "Method " + testMethod + " depends on not successfully finished methods";
1519627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      }
1520f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1521f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1522627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    return null;
1523f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1524f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1525f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1526bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust   * @return the test results that apply to one of the instances of the testMethod.
1527bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust   */
1528bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  private Set<ITestResult> keepSameInstances(ITestNGMethod method, Set<ITestResult> results) {
1529bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    Set<ITestResult> result = Sets.newHashSet();
1530bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    for (ITestResult r : results) {
15316293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin      final Object o = method.getInstance();
15329cb7e93d4f995f0003b27a1f28dc9d939b9b8a36Cédric Beust        // Keep this instance if 1) It's on a different class or 2) It's on the same class
15339cb7e93d4f995f0003b27a1f28dc9d939b9b8a36Cédric Beust        // and on the same instance
153460916e4ddae15723de42347024800d514b85de09Cédric Beust        Object instance = r.getInstance() != null
15356293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin            ? r.getInstance() : r.getMethod().getInstance();
153660916e4ddae15723de42347024800d514b85de09Cédric Beust        if (r.getTestClass() != method.getTestClass() || instance == o) result.add(r);
1537bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    }
1538bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    return result;
1539bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  }
1540bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust
1541bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  /**
1542f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if all the methods have been run successfully
1543f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1544bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  private boolean haveBeenRunSuccessfully(ITestNGMethod testMethod, ITestNGMethod[] methods) {
1545f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Make sure the method has been run successfully
15460f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    for (ITestNGMethod method : methods) {
1547bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust      Set<ITestResult> results = keepSameInstances(testMethod, m_notifier.getPassedTests(method));
154860916e4ddae15723de42347024800d514b85de09Cédric Beust      Set<ITestResult> failedAndSkippedMethods = Sets.newHashSet();
154960916e4ddae15723de42347024800d514b85de09Cédric Beust      failedAndSkippedMethods.addAll(m_notifier.getFailedTests(method));
155060916e4ddae15723de42347024800d514b85de09Cédric Beust      failedAndSkippedMethods.addAll(m_notifier.getSkippedTests(method));
155160916e4ddae15723de42347024800d514b85de09Cédric Beust      Set<ITestResult> failedresults = keepSameInstances(testMethod, failedAndSkippedMethods);
155289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1553bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust      // If failed results were returned on the same instance, then these tests didn't pass
15540f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if (failedresults != null && failedresults.size() > 0) {
15550f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        return false;
15560f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
155789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1558f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (ITestResult result : results) {
1559f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(!result.isSuccess()) {
1560f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          return false;
1561f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1562f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1563f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1564f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1565f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return true;
1566f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1567f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
156810a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//  private boolean containsInstance(Set<ITestResult> failedresults, Object[] instances) {
156910a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//    for (ITestResult tr : failedresults) {
157010a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//      for (Object o : instances) {
157110a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//        if (o == tr.getInstance()) {
157210a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//          return true;
157310a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//        }
157410a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//      }
157510a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//    }
157610a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//    return false;
157710a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//  }
1578bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust
1579f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1580f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * An exception was thrown by the test, determine if this method
1581f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * should be marked as a failure or as failure_but_within_successPercentage
1582f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1583f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void handleException(Throwable throwable,
1584f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               ITestNGMethod testMethod,
1585f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               ITestResult testResult,
1586f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               int failureCount) {
1587dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    if (throwable != null) {
1588dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      testResult.setThrowable(throwable);
1589dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    }
1590f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int successPercentage= testMethod.getSuccessPercentage();
1591f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int invocationCount= testMethod.getInvocationCount();
159221dad3370294d6595fdddc3faf55792f60a913f1nullin    float numberOfTestsThatCanFail= ((100 - successPercentage) * invocationCount) / 100f;
1593f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1594f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(failureCount < numberOfTestsThatCanFail) {
1595f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.SUCCESS_PERCENTAGE_FAILURE);
1596f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1597f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else {
1598f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.FAILURE);
1599f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1600f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1601f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1602f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16039d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  static interface Predicate<K, T> {
16049d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    boolean isTrue(K k, T v);
16059d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  }
1606f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16079d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  static class CanRunFromClassPredicate implements Predicate <ITestNGMethod, IClass> {
16089d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    @Override
16099d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    public boolean isTrue(ITestNGMethod m, IClass v) {
16109d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      return m.canRunFromClass(v);
1611f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1612f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1613f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16149d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  static class SameClassNamePredicate implements Predicate<ITestNGMethod, IClass> {
16159d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    @Override
16169d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    public boolean isTrue(ITestNGMethod m, IClass c) {
16179d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      return c == null || m.getTestClass().getName().equals(c.getName());
1618f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
16199d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  }
1620f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16219d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  /**
16229d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust   * @return Only the ITestNGMethods applicable for this testClass
16239d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust   */
16249d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  private ITestNGMethod[] filterMethods(IClass testClass, ITestNGMethod[] methods,
16259d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      Predicate<ITestNGMethod, IClass> predicate) {
1626ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestNGMethod> vResult= Lists.newArrayList();
1627f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1628f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(ITestNGMethod tm : methods) {
16299d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      if (predicate.isTrue(tm, testClass)) {
16309d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust        log(10, "Keeping method " + tm + " for class " + testClass);
1631f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        vResult.add(tm);
16329d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      } else {
16339d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust        log(10, "Filtering out method " + tm + " for class " + testClass);
1634f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1635f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1636f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16379d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    ITestNGMethod[] result= vResult.toArray(new ITestNGMethod[vResult.size()]);
16389d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust
16399d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    return result;
1640f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1641f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1642f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
16436671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin   * @return true if this method depends on certain methods.
1644f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1645f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean dependsOnMethods(ITestNGMethod tm) {
1646e934f66fb4fb247ebf5fec45770bc6820fbba29anullin    String[] methods = tm.getMethodsDependedUpon();
16476671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin    return null != methods && methods.length > 0;
1648f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1649f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1650ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust  private void runConfigurationListeners(ITestResult tr, boolean before) {
1651ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    if (before) {
1652ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust      for(IConfigurationListener icl: m_notifier.getConfigurationListeners()) {
1653eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beust        if (icl instanceof IConfigurationListener2) {
1654eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beust          ((IConfigurationListener2) icl).beforeConfiguration(tr);
1655eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beust        }
1656ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust      }
1657ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    } else {
1658ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust      for(IConfigurationListener icl: m_notifier.getConfigurationListeners()) {
1659ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust        switch(tr.getStatus()) {
1660ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust          case ITestResult.SKIP:
1661ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            icl.onConfigurationSkip(tr);
1662ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            break;
1663ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust          case ITestResult.FAILURE:
1664ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            icl.onConfigurationFailure(tr);
1665ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            break;
1666ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust          case ITestResult.SUCCESS:
1667ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            icl.onConfigurationSuccess(tr);
1668ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            break;
1669ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust        }
1670f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1671f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1672f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
167389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1674c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust  void runTestListeners(ITestResult tr) {
1675f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    runTestListeners(tr, m_notifier.getTestListeners());
1676f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
167789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1678f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  // TODO: move this from here as it is directly called from TestNG
1679f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public static void runTestListeners(ITestResult tr, List<ITestListener> listeners) {
1680f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (ITestListener itl : listeners) {
1681f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      switch(tr.getStatus()) {
1682f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SKIP: {
1683f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestSkipped(tr);
1684f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1685f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1686f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SUCCESS_PERCENTAGE_FAILURE: {
1687f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestFailedButWithinSuccessPercentage(tr);
1688f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1689f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1690f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.FAILURE: {
1691f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestFailure(tr);
1692f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1693f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1694f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SUCCESS: {
1695f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestSuccess(tr);
1696f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1697f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1698f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1699f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.STARTED: {
1700f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestStart(tr);
1701f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1702f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1703f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1704f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        default: {
1705f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          assert false : "UNKNOWN STATUS:" + tr;
1706f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1707f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1708f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1709f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1710f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1711f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void log(int level, String s) {
1712f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Utils.log("Invoker " + Thread.currentThread().hashCode(), level, s);
1713f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
171489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1715eddb4a9423c14fee808a30e92ad77a16e88b320enullin  /**
1716c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin   * This class holds a {@code ParameterHolder} or in case of an error, a non-null
1717eddb4a9423c14fee808a30e92ad77a16e88b320enullin   * {@code TestResult} containing the cause
1718eddb4a9423c14fee808a30e92ad77a16e88b320enullin   */
1719f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private static class ParameterBag {
1720c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust    final ParameterHolder parameterHolder;
1721c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    final ITestResult errorResult;
172289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1723c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    public ParameterBag(ParameterHolder parameterHolder) {
1724c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.parameterHolder = parameterHolder;
1725c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.errorResult = null;
1726c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    }
1727c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin
1728c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    public ParameterBag(ITestResult errorResult) {
1729c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.parameterHolder = null;
1730c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.errorResult = errorResult;
1731f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
173289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1733f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public boolean hasErrors() {
1734c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      return errorResult != null;
1735f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1736f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1737c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust
1738f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust}
1739