Invoker.java revision f594497ff6fd02ece89f19975bb074d5ef87261b
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;
140bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beustimport org.testng.IConfigurable;
15ee8e37d41d7e14252ee649f13768022fee714afbCédric Beustimport org.testng.IConfigurationListener;
16eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beustimport org.testng.IConfigurationListener2;
17f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IHookable;
18398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beustimport org.testng.IInvokedMethod;
1938ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beustimport org.testng.IInvokedMethodListener;
20f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IRetryAnalyzer;
21f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestClass;
22f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestContext;
23f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestListener;
24f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestNGMethod;
25f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestResult;
26f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.Reporter;
27f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.SkipException;
28f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.SuiteRunState;
29f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.TestException;
30f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.TestNGException;
312d568355761a9632bf24a87984e241f8a079d724Cédric Beustimport org.testng.annotations.IConfigurationAnnotation;
32aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beustimport org.testng.annotations.NoInjection;
33ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beustimport org.testng.collections.Lists;
340f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.collections.Maps;
35e9a829e47a3f321807f9f3b6a15ec98ab6e22b98Julien Herrimport org.testng.collections.Sets;
36f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.InvokeMethodRunnable.TestNGRuntimeException;
379150cdf3bacb4715cee345cd153d4f0ab3dbd198nullinimport org.testng.internal.ParameterHolder.ParameterOrigin;
38f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.annotations.AnnotationHelper;
39f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.annotations.IAnnotationFinder;
4092d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermannimport org.testng.internal.invokers.InvokedMethodListenerInvoker;
4192d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermannimport org.testng.internal.invokers.InvokedMethodListenerMethod;
42f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.thread.ThreadExecutionException;
43f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.thread.ThreadUtil;
44f035a01bd8ac47425984d6b9e07a733f3abb3c37nullinimport org.testng.internal.thread.graph.IWorker;
45f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlClass;
46f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlSuite;
47f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlTest;
48f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
49ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport static org.testng.internal.invokers.InvokedMethodListenerMethod.AFTER_INVOCATION;
50ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beustimport static org.testng.internal.invokers.InvokedMethodListenerMethod.BEFORE_INVOCATION;
51423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust
52f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust/**
53f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * This class is responsible for invoking methods:
54f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - test methods
55f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - configuration methods
56f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - possibly in a separate thread
57f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * and then for notifying the result listeners.
58f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust *
59f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
60f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
61f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust */
62f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustpublic class Invoker implements IInvoker {
6321dad3370294d6595fdddc3faf55792f60a913f1nullin  private final ITestContext m_testContext;
6421dad3370294d6595fdddc3faf55792f60a913f1nullin  private final ITestResultNotifier m_notifier;
6521dad3370294d6595fdddc3faf55792f60a913f1nullin  private final IAnnotationFinder m_annotationFinder;
6621dad3370294d6595fdddc3faf55792f60a913f1nullin  private final SuiteRunState m_suiteState;
67eddb4a9423c14fee808a30e92ad77a16e88b320enullin  private final boolean m_skipFailedInvocationCounts;
6821dad3370294d6595fdddc3faf55792f60a913f1nullin  private final List<IInvokedMethodListener> m_invokedMethodListeners;
69eddb4a9423c14fee808a30e92ad77a16e88b320enullin  private final boolean m_continueOnFailedConfiguration;
7089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
7121dad3370294d6595fdddc3faf55792f60a913f1nullin  /** Group failures must be synced as the Invoker is accessed concurrently */
72423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  private Map<String, Boolean> m_beforegroupsFailures = Maps.newHashtable();
7389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
7421dad3370294d6595fdddc3faf55792f60a913f1nullin  /** Class failures must be synced as the Invoker is accessed concurrently */
75f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin  private Map<Class<?>, Set<Object>> m_classInvocationResults = Maps.newHashtable();
7689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
7762a82c6aa5725c9e9d600af5ee06a5852100208cnullin  /** Test methods whose configuration methods have failed. */
78f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin  private Map<ITestNGMethod, Set<Object>> m_methodInvocationResults = Maps.newHashtable();
793297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust  private IConfiguration m_configuration;
8089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
819d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  /** Predicate to filter methods */
829eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust  private static Predicate<ITestNGMethod, IClass> CAN_RUN_FROM_CLASS = new CanRunFromClassPredicate();
839d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  /** Predicate to filter methods */
849eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust  private static final Predicate<ITestNGMethod, IClass> SAME_CLASS = new SameClassNamePredicate();
859d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust
86423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  private void setClassInvocationFailure(Class<?> clazz, Object instance) {
87f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    Set<Object> instances = m_classInvocationResults.get( clazz );
88423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    if (instances == null) {
89f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      instances = Sets.newHashSet();
90423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      m_classInvocationResults.put(clazz, instances);
91423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    }
92423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    instances.add(instance);
9362a82c6aa5725c9e9d600af5ee06a5852100208cnullin  }
9489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
95423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  private void setMethodInvocationFailure(ITestNGMethod method, Object instance) {
96f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    Set<Object> instances = m_methodInvocationResults.get(method);
97423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    if (instances == null) {
98f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      instances = Sets.newHashSet();
99423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      m_methodInvocationResults.put(method, instances);
100423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    }
1012084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq    instances.add(getMethodInvocationToken(method, instance));
10262a82c6aa5725c9e9d600af5ee06a5852100208cnullin  }
103f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1043297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust  public Invoker(IConfiguration configuration,
1053297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust                 ITestContext testContext,
106f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                 ITestResultNotifier notifier,
107f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                 SuiteRunState state,
10838ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beust                 boolean skipFailedInvocationCounts,
109398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust                 List<IInvokedMethodListener> invokedMethodListeners) {
1103297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust    m_configuration = configuration;
111f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_testContext= testContext;
112f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_suiteState= state;
113f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_notifier= notifier;
1143297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust    m_annotationFinder= configuration.getAnnotationFinder();
1156cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust    m_skipFailedInvocationCounts = skipFailedInvocationCounts;
116398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust    m_invokedMethodListeners = invokedMethodListeners;
11762a82c6aa5725c9e9d600af5ee06a5852100208cnullin    m_continueOnFailedConfiguration = XmlSuite.CONTINUE.equals(testContext.getSuite().getXmlSuite().getConfigFailurePolicy());
118f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
119f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
120f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
121f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Invoke configuration methods if they belong to the same TestClass passed
122f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * in parameter.. <p/>TODO: Calculate ahead of time which methods should be
123f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * invoked for each class. Might speed things up for users who invoke the
124f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * same test class with different parameters in the same suite run.
125f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   *
126f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * If instance is non-null, the configuration will be run on it.  If it is null,
127f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * the configuration methods will be run on all the instances retrieved
128f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * from the ITestClass.
129f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
130423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  @Override
131f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public void invokeConfigurations(IClass testClass,
132f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] allMethods,
133f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
134f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
135facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                                   Object[] parameterValues,
136f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Object instance)
137f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
138da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust    invokeConfigurations(testClass, null, allMethods, suite, params, parameterValues, instance,
139da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust        null);
140f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
141f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
142f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void invokeConfigurations(IClass testClass,
143f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod currentTestMethod,
144f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] allMethods,
145f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
146f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
147facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                                   Object[] parameterValues,
148da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                                   Object instance,
149da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                                   ITestResult testMethodResult)
150f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
151f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == allMethods) {
152161d9860588ad89389848d70eb0a2f6f0cb46d1bCédric Beust      log(5, "No configuration methods found");
153f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
154f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return;
155f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
156f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1579d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    ITestNGMethod[] methods= filterMethods(testClass, allMethods, SAME_CLASS);
158f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
159f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(ITestNGMethod tm : methods) {
160f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(null == testClass) {
161f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testClass= tm.getTestClass();
162f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
163f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      ITestResult testResult= new TestResult(testClass,
165f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             instance,
166f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             tm,
167f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             null,
168f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             System.currentTimeMillis(),
1696f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                             System.currentTimeMillis(),
1706f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                             m_testContext);
171f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1722d568355761a9632bf24a87984e241f8a079d724Cédric Beust      IConfigurationAnnotation configurationAnnotation= null;
173f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      try {
1746293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin        Object inst = tm.getInstance();
1756293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin        if (inst == null) {
1766293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin          inst = instance;
1770f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        }
1786293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin        Class<?> objectClass= inst.getClass();
179f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Method method= tm.getMethod();
180f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
181f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Only run the configuration if
182f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // - the test is enabled and
183f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // - the Configuration method belongs to the same class or a parent
184328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        configurationAnnotation = AnnotationHelper.findConfiguration(m_annotationFinder, method);
185328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        boolean alwaysRun= isAlwaysRun(configurationAnnotation);
186328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        if(MethodHelper.isEnabled(objectClass, m_annotationFinder) || alwaysRun) {
187f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
188e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust          if (MethodHelper.isEnabled(configurationAnnotation)) {
18989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
190423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust            if (!confInvocationPassed(tm, currentTestMethod, testClass, instance) && !alwaysRun) {
191423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust              handleConfigurationSkip(tm, testResult, configurationAnnotation, currentTestMethod, instance, suite);
192e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust              continue;
193e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            }
19489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
195e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            log(3, "Invoking " + Utils.detailedMethodName(tm, true));
19689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
197facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust            Object[] parameters = Parameters.createConfigurationParameters(tm.getMethod(),
198facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                params,
199facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                parameterValues,
200facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                currentTestMethod,
201facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                m_annotationFinder,
202facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust                suite,
203da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                m_testContext,
204da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust                testMethodResult);
205e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            testResult.setParameters(parameters);
20689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
2073cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin            Object newInstance = null != instance ? instance: inst;
20889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
209ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            runConfigurationListeners(testResult, true /* before */);
210ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust
2113cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin            invokeConfigurationMethod(newInstance, tm,
21200234ed4e19c38374d0bbd5bc2de771c90b16209Julien Herr              parameters, testResult);
21389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
214e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            // TODO: probably we should trigger the event for each instance???
215e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            testResult.setEndMillis(System.currentTimeMillis());
216ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            runConfigurationListeners(testResult, false /* after */);
217e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust          }
218e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust          else {
219e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust            log(3,
220e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust                "Skipping "
221e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust                + Utils.detailedMethodName(tm, true)
222e0d94c7896da2777a41a10ed3efcf5231e76f907Cédric Beust                + " because it is not enabled");
223f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
224f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        } // if is enabled
225f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else {
226f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          log(3,
227f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              "Skipping "
228f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + Utils.detailedMethodName(tm, true)
229f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + " because "
230f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + objectClass.getName()
231f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + " is not enabled");
232f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
233f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
234f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      catch(InvocationTargetException ex) {
235423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, currentTestMethod, instance, suite);
236a3f78c5debcd03e7755f5ff2956a6f325e41d0b7Ryan Schmitt      } catch(Throwable ex) { // covers the non-wrapper exceptions
237423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, currentTestMethod, instance, suite);
238f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
239f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // for methods
240f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
24189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
242f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
24362a82c6aa5725c9e9d600af5ee06a5852100208cnullin   * Marks the current <code>TestResult</code> as skipped and invokes the listeners.
244f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
24589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void handleConfigurationSkip(ITestNGMethod tm,
24689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                       ITestResult testResult,
24789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                       IConfigurationAnnotation annotation,
24889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                       ITestNGMethod currentTestMethod,
249423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust                                       Object instance,
25062a82c6aa5725c9e9d600af5ee06a5852100208cnullin                                       XmlSuite suite) {
251423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust    recordConfigurationInvocationFailed(tm, testResult.getTestClass(), annotation, currentTestMethod, instance, suite);
252f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    testResult.setStatus(ITestResult.SKIP);
253ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    runConfigurationListeners(testResult, false /* after */);
254f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
25589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
256f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
257f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Is the <code>IConfiguration</code> marked as alwaysRun.
258f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
2592d568355761a9632bf24a87984e241f8a079d724Cédric Beust  private boolean isAlwaysRun(IConfigurationAnnotation configurationAnnotation) {
260f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == configurationAnnotation) {
261f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return false;
262f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
26389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
264f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean alwaysRun= false;
265f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if ((configurationAnnotation.getAfterSuite()
266f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        || configurationAnnotation.getAfterTest()
267f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        || configurationAnnotation.getAfterTestClass()
268328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getAfterTestMethod()
269328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeTestMethod()
270328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeTestClass()
271328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeTest()
272328620f61d3ea7fb5d12cfd9ee659c755a5468fcJulien Herr        || configurationAnnotation.getBeforeSuite())
273f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        && configurationAnnotation.getAlwaysRun())
274f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    {
275f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        alwaysRun= true;
276f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
27789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
278f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return alwaysRun;
279f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
28089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
281f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void handleConfigurationFailure(Throwable ite,
282f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          ITestNGMethod tm,
283f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          ITestResult testResult,
2842d568355761a9632bf24a87984e241f8a079d724Cédric Beust                                          IConfigurationAnnotation annotation,
28562a82c6aa5725c9e9d600af5ee06a5852100208cnullin                                          ITestNGMethod currentTestMethod,
286423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust                                          Object instance,
28789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                          XmlSuite suite)
288f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
289f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Throwable cause= ite.getCause() != null ? ite.getCause() : ite;
29089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
2916671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin    if(isSkipExceptionAndSkip(cause)) {
2926671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin      testResult.setThrowable(cause);
2936671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin      handleConfigurationSkip(tm, testResult, annotation, currentTestMethod, instance, suite);
2946671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin      return;
295f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
296161d9860588ad89389848d70eb0a2f6f0cb46d1bCédric Beust    Utils.log("", 3, "Failed to invoke configuration method "
297f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        + tm.getRealClass().getName() + "." + tm.getMethodName() + ":" + cause.getMessage());
298f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    handleException(cause, tm, testResult, 1);
299ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    runConfigurationListeners(testResult, false /* after */);
300f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
30189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    //
302f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If in TestNG mode, need to take a look at the annotation to figure out
303f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // what kind of @Configuration method we're dealing with
304f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
305f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (null != annotation) {
306423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      recordConfigurationInvocationFailed(tm, testResult.getTestClass(), annotation, currentTestMethod, instance, suite);
307f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
308f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
309f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
310f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
311f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return All the classes that belong to the same <test> tag as @param cls
312f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
313f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private XmlClass[] findClassesInSameTest(Class<?> cls, XmlSuite suite) {
3140f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust    Map<String, XmlClass> vResult= Maps.newHashMap();
315f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String className= cls.getName();
316f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(XmlTest test : suite.getTests()) {
317f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(XmlClass testClass : test.getXmlClasses()) {
318f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(testClass.getName().equals(className)) {
319f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
320f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // Found it, add all the classes in this test in the result
321f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          for(XmlClass thisClass : test.getXmlClasses()) {
322f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            vResult.put(thisClass.getName(), thisClass);
323f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
324f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // Note:  we need to iterate through the entire suite since the same
325f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // class might appear in several <test> tags
326f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
327f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
328f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
329f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
330f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    XmlClass[] result= vResult.values().toArray(new XmlClass[vResult.size()]);
331f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
332f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
333f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
334f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
335f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
336f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Record internally the failure of a Configuration, so that we can determine
337f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * later if @Test should be skipped.
338f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
33989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void recordConfigurationInvocationFailed(ITestNGMethod tm,
34089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                   IClass testClass,
34189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                   IConfigurationAnnotation annotation,
34289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                   ITestNGMethod currentTestMethod,
343423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust                                                   Object instance,
34462a82c6aa5725c9e9d600af5ee06a5852100208cnullin                                                   XmlSuite suite) {
34562a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // If beforeTestClass or afterTestClass failed, mark either the config method's
34662a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // entire class as failed, or the class under tests as failed, depending on
34762a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // the configuration failure policy
34862a82c6aa5725c9e9d600af5ee06a5852100208cnullin    if (annotation.getBeforeTestClass() || annotation.getAfterTestClass()) {
34962a82c6aa5725c9e9d600af5ee06a5852100208cnullin      // tm is the configuration method, and currentTestMethod is null for BeforeClass
35062a82c6aa5725c9e9d600af5ee06a5852100208cnullin      // methods, so we need testClass
35162a82c6aa5725c9e9d600af5ee06a5852100208cnullin      if (m_continueOnFailedConfiguration) {
352423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(testClass.getRealClass(), instance);
35362a82c6aa5725c9e9d600af5ee06a5852100208cnullin      } else {
354423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(tm.getRealClass(), instance);
35562a82c6aa5725c9e9d600af5ee06a5852100208cnullin      }
35662a82c6aa5725c9e9d600af5ee06a5852100208cnullin    }
35789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
35862a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // If before/afterTestMethod failed, mark either the config method's entire
35962a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // class as failed, or just the current test method as failed, depending on
36062a82c6aa5725c9e9d600af5ee06a5852100208cnullin    // the configuration failure policy
36162a82c6aa5725c9e9d600af5ee06a5852100208cnullin    else if (annotation.getBeforeTestMethod() || annotation.getAfterTestMethod()) {
36262a82c6aa5725c9e9d600af5ee06a5852100208cnullin      if (m_continueOnFailedConfiguration) {
363423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setMethodInvocationFailure(currentTestMethod, instance);
36462a82c6aa5725c9e9d600af5ee06a5852100208cnullin      } else {
365423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(tm.getRealClass(), instance);
36662a82c6aa5725c9e9d600af5ee06a5852100208cnullin      }
367f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
368f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
369f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If beforeSuite or afterSuite failed, mark *all* the classes as failed
370f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // for configurations.  At this point, the entire Suite is screwed
371f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else if (annotation.getBeforeSuite() || annotation.getAfterSuite()) {
372f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_suiteState.failed();
373f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
374f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
375f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // beforeTest or afterTest:  mark all the classes in the same
376f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // <test> stanza as failed for configuration
377f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else if (annotation.getBeforeTest() || annotation.getAfterTest()) {
378423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      setClassInvocationFailure(tm.getRealClass(), instance);
379f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlClass[] classes= findClassesInSameTest(tm.getRealClass(), suite);
380f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(XmlClass xmlClass : classes) {
381423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust        setClassInvocationFailure(xmlClass.getSupportClass(), instance);
382f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
383f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
384f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] beforeGroups= annotation.getBeforeGroups();
385f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null != beforeGroups && beforeGroups.length > 0) {
386f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(String group: beforeGroups) {
387f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        m_beforegroupsFailures.put(group, Boolean.FALSE);
388f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
389f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
390f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
39189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
392f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
3932723c0384d932da07d978701ae8247ae5086ba38Cédric Beust   * @return true if this class or a parent class failed to initialize.
3942723c0384d932da07d978701ae8247ae5086ba38Cédric Beust   */
3952723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  private boolean classConfigurationFailed(Class<?> cls) {
3962723c0384d932da07d978701ae8247ae5086ba38Cédric Beust    for (Class<?> c : m_classInvocationResults.keySet()) {
3975472868e8d0434658827e3ebf479a37992012d46Julien Herr      if (c == cls || c.isAssignableFrom(cls)) {
3982723c0384d932da07d978701ae8247ae5086ba38Cédric Beust        return true;
3992723c0384d932da07d978701ae8247ae5086ba38Cédric Beust      }
4002723c0384d932da07d978701ae8247ae5086ba38Cédric Beust    }
4012723c0384d932da07d978701ae8247ae5086ba38Cédric Beust    return false;
4022723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  }
4032723c0384d932da07d978701ae8247ae5086ba38Cédric Beust
4042723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  /**
405f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if this class has successfully run all its @Configuration
406f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * method or false if at least one of these methods failed.
407f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
4082723c0384d932da07d978701ae8247ae5086ba38Cédric Beust  private boolean confInvocationPassed(ITestNGMethod method, ITestNGMethod currentTestMethod,
4092723c0384d932da07d978701ae8247ae5086ba38Cédric Beust      IClass testClass, Object instance) {
410f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean result= true;
411f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
4129637d33cffacd41cf92ca042ff59188e3d09ddd1Julien Herr    Class<?> cls = testClass.getRealClass();
41362a82c6aa5725c9e9d600af5ee06a5852100208cnullin
414f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(m_suiteState.isFailed()) {
415f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      result= false;
416f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
417f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else {
4182723c0384d932da07d978701ae8247ae5086ba38Cédric Beust      if (classConfigurationFailed(cls)) {
4190f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        if (! m_continueOnFailedConfiguration) {
4202723c0384d932da07d978701ae8247ae5086ba38Cédric Beust          result = !classConfigurationFailed(cls);
4210f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        } else {
4220f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          result = !m_classInvocationResults.get(cls).contains(instance);
4230f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        }
424f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
42562a82c6aa5725c9e9d600af5ee06a5852100208cnullin      // if method is BeforeClass, currentTestMethod will be null
42689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      else if (m_continueOnFailedConfiguration &&
42789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              currentTestMethod != null &&
42862a82c6aa5725c9e9d600af5ee06a5852100208cnullin              m_methodInvocationResults.containsKey(currentTestMethod)) {
4292084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq        result = !m_methodInvocationResults.get(currentTestMethod).contains(getMethodInvocationToken(currentTestMethod, instance));
43062a82c6aa5725c9e9d600af5ee06a5852100208cnullin      }
431423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust      else if (! m_continueOnFailedConfiguration) {
432f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        for(Class<?> clazz: m_classInvocationResults.keySet()) {
4331e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust//          if (clazz == cls) {
434f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          if(clazz.isAssignableFrom(cls)) {
435f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            result= false;
436f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            break;
437f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
438f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
439f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
440f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
441f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
442f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // check if there are failed @BeforeGroups
443f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] groups= method.getGroups();
444f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null != groups && groups.length > 0) {
445f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(String group: groups) {
446f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(m_beforegroupsFailures.containsKey(group)) {
447f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          result= false;
448f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
449f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
450f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
451f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
452f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
453f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
454f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
4552084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq   // Creates a token for tracking a unique invocation of a method on an instance.
4562084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq   // Is used when configFailurePolicy=continue.
4572084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq  private Object getMethodInvocationToken(ITestNGMethod method, Object instance) {
4582084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq    return String.format("%s+%d", instance.toString(), method.getCurrentInvocationCount());
4592084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq  }
4602084500c0b9f7e95d1accfe5ff2c48ee0747aac6toddq
461f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
462f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Effectively invokes a configuration method on all passed in instances.
463d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com   * TODO: Should change this method to be more like invokeMethod() so that we can
464d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com   * handle calls to {@code IInvokedMethodListener} better.
46589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   *
4663cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin   * @param targetInstance the instance to invoke the configuration method on
467f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param tm the configuration method
468f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param params the parameters needed for method invocation
469f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param testResult
470f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @throws InvocationTargetException
471f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @throws IllegalAccessException
472f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
4733cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin  private void invokeConfigurationMethod(Object targetInstance,
474f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         ITestNGMethod tm,
475f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         Object[] params,
476f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         ITestResult testResult)
47789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    throws InvocationTargetException, IllegalAccessException
478f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
479f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Mark this method with the current thread id
480f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    tm.setId(ThreadUtil.currentThreadInfo());
481f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
4823cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin    {
48392d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      InvokedMethod invokedMethod= new InvokedMethod(targetInstance,
484f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          tm,
485f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          params,
486234c85874acc0cd3360639949fbd566255ab31edCédric Beust                                          System.currentTimeMillis(),
487234c85874acc0cd3360639949fbd566255ab31edCédric Beust                                          testResult);
488f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
48992d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      runInvokedMethodListeners(BEFORE_INVOCATION, invokedMethod, testResult);
49092d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      m_notifier.addInvokedMethod(invokedMethod);
491f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      try {
492f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Reporter.setCurrentTestResult(testResult);
4930bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        Method method = tm.getMethod();
494e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust
495e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        //
4963cf15f7c4f97abc02efe1f03a3a81d78210d80c1Vladislav Rassokhin        // If this method is a IConfigurable, invoke its run() method
497e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        //
498e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        IConfigurable configurableInstance =
499e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust          IConfigurable.class.isAssignableFrom(tm.getMethod().getDeclaringClass()) ?
500e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust          (IConfigurable) targetInstance : m_configuration.getConfigurable();
501e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust        if (configurableInstance != null) {
502b1c182d51b05a40ac5350e562503a94d024a7c80nullin          MethodInvocationHelper.invokeConfigurable(targetInstance, params, configurableInstance, method,
503e14d0686c991db20dacf627becc3d162a9f35f90Cédric Beust              testResult);
5040bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        }
5050bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        else {
5060bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust          //
507830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          // Not a IConfigurable, invoke directly
5080bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust          //
509830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          if (MethodHelper.calculateTimeOut(tm) <= 0) {
510b1c182d51b05a40ac5350e562503a94d024a7c80nullin            MethodInvocationHelper.invokeMethod(method, targetInstance, params);
511830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          }
512830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          else {
513b1c182d51b05a40ac5350e562503a94d024a7c80nullin            MethodInvocationHelper.invokeWithTimeout(tm, targetInstance, params, testResult);
514830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust            if (!testResult.isSuccess()) {
515830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust              // A time out happened
516830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust              throwConfigurationFailure(testResult, testResult.getThrowable());
517830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust              throw testResult.getThrowable();
518830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust            }
519830ff4bf3fbfae0d63cb762b9c0d9a184feb58a3Cédric Beust          }
5200bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        }
521db66a3de4428040dd9f7e377a3b6835965c8b0cdCédric Beust      }
522a3f78c5debcd03e7755f5ff2956a6f325e41d0b7Ryan Schmitt      catch (InvocationTargetException | IllegalAccessException ex) {
5230bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust       throwConfigurationFailure(testResult, ex);
5240bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust       throw ex;
525a3f78c5debcd03e7755f5ff2956a6f325e41d0b7Ryan Schmitt      } catch (Throwable ex) {
5260bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        throwConfigurationFailure(testResult, ex);
5270bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust        throw new TestNGException(ex);
5280bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust      }
5290bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust      finally {
530f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Reporter.setCurrentTestResult(testResult);
53192d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann        runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult);
532b1d4c2115043263424f47656ec336a5e5d9098f7Cédric Beust        Reporter.setCurrentTestResult(null);
53389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      }
534f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
535f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
536f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
5370bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust  private void throwConfigurationFailure(ITestResult testResult, Throwable ex)
5380bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust  {
5390bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust    testResult.setStatus(ITestResult.FAILURE);;
5400bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust    testResult.setThrowable(ex.getCause() == null ? ex : ex.getCause());
5410bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust  }
5420bc5acb68f6cace8b7f8b07e2eebc6f385c337e0Cédric Beust
54392d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann  private void runInvokedMethodListeners(InvokedMethodListenerMethod listenerMethod, IInvokedMethod invokedMethod,
544398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust      ITestResult testResult)
545398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust  {
54692d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    if ( noListenersPresent() ) {
54792d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      return;
548398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust    }
54992d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann
55092d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    InvokedMethodListenerInvoker invoker = new InvokedMethodListenerInvoker(listenerMethod, testResult, m_testContext);
55192d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    for (IInvokedMethodListener currentListener : m_invokedMethodListeners) {
55292d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      invoker.invokeListener(currentListener, invokedMethod);
55392d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    }
55492d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann  }
55592d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann
55692d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann  private boolean noListenersPresent() {
55792d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann    return (m_invokedMethodListeners == null) || (m_invokedMethodListeners.size() == 0);
558398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust  }
559398dbfd526cb7a568c29cc4a211d5cb8a7a158bcCédric Beust
560927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust  // pass both paramValues and paramIndex to be thread safe in case parallel=true + dataprovider.
5616293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin  private ITestResult invokeMethod(Object instance,
562f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   final ITestNGMethod tm,
563f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Object[] parameterValues,
564927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust                                   int parametersIndex,
565f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
566f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
567f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestClass testClass,
568f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] beforeMethods,
569f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] afterMethods,
5706b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                   ConfigurationGroupMethods groupMethods,
5716b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                   FailureContext failureContext) {
57294efdf8e6ac7332eadf8bfe5d1fe699caee5d051Cédric Beust    TestResult testResult = new TestResult();
57394efdf8e6ac7332eadf8bfe5d1fe699caee5d051Cédric Beust
574f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
575f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Invoke beforeGroups configurations
576f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
577f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    invokeBeforeGroupsConfigurations(testClass, tm, groupMethods, suite, params,
5783297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust        instance);
579f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
580f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
58145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // Invoke beforeMethods only if
58245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // - firstTimeOnly is not set
58345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // - firstTimeOnly is set, and we are reaching at the first invocationCount
584f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
58589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    invokeConfigurations(testClass, tm,
58645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      filterConfigurationMethods(tm, beforeMethods, true /* beforeMethods */),
587facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust      suite, params, parameterValues,
5883297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      instance, testResult);
58989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
590f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
591f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Create the ExtraOutput for this method
592f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
59338ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beust    InvokedMethod invokedMethod = null;
594f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    try {
5953297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      testResult.init(testClass, instance,
596f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 tm,
597f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 null,
598f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 System.currentTimeMillis(),
5996f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                 0,
6006f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                                 m_testContext);
601f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setParameters(parameterValues);
602f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setHost(m_testContext.getHost());
603f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.STARTED);
604f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
6053297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      invokedMethod= new InvokedMethod(instance,
606f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          tm,
607f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          parameterValues,
608234c85874acc0cd3360639949fbd566255ab31edCédric Beust          System.currentTimeMillis(),
609234c85874acc0cd3360639949fbd566255ab31edCédric Beust          testResult);
610f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
611272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // Fix from ansgarkonermann
612272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // invokedMethod is used in the finally, which can be invoked if
613272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // any of the test listeners throws an exception, therefore,
614272431b36621155717086ce4a384855f3003fff1Ansgar Konermann      // invokedMethod must have a value before we get here
61559d29c5fddc09eb6dc132569b0f4c4026f033b1aAnsgar Konermann      runTestListeners(testResult);
61659d29c5fddc09eb6dc132569b0f4c4026f033b1aAnsgar Konermann
61792d93309b4eca03e639a5b027e484ac52f049ef1Ansgar Konermann      runInvokedMethodListeners(BEFORE_INVOCATION, invokedMethod, testResult);
61838ef90d96ee65073c1090455e7caff2a85d654e2Cédric Beust
619f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_notifier.addInvokedMethod(invokedMethod);
62089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
621dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      Method thisMethod = tm.getConstructorOrMethod().getMethod();
62289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
6233297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust      if(confInvocationPassed(tm, tm, testClass, instance)) {
624dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        log(3, "Invoking " + tm.getRealClass().getName() + "." + tm.getMethodName());
625f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
6268e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        Reporter.setCurrentTestResult(testResult);
6278e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr
6288e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        // If this method is a IHookable, invoke its run() method
6298e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        IHookable hookableInstance =
6308e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr            IHookable.class.isAssignableFrom(tm.getRealClass()) ?
6313b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust            (IHookable) instance : m_configuration.getHookable();
6328e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr
6338e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        if (MethodHelper.calculateTimeOut(tm) <= 0) {
6343b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust          if (hookableInstance != null) {
6353b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust            MethodInvocationHelper.invokeHookable(instance,
6363b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust                parameterValues, hookableInstance, thisMethod, testResult);
6378e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr          } else {
6388e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr            // Not a IHookable, invoke directly
6393b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust            MethodInvocationHelper.invokeMethod(thisMethod, instance,
6403b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust                parameterValues);
641f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
6423b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust          testResult.setStatus(ITestResult.SUCCESS);
6438e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr        } else {
644331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust          // Method with a timeout
6458e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr          MethodInvocationHelper.invokeWithTimeout(tm, instance, parameterValues, testResult, hookableInstance);
646f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
647f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
648f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
649f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setStatus(ITestResult.SKIP);
650f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
651f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
652f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(InvocationTargetException ite) {
653f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setThrowable(ite.getCause());
654d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com      testResult.setStatus(ITestResult.FAILURE);
655f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
656f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(ThreadExecutionException tee) { // wrapper for TestNGRuntimeException
657f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Throwable cause= tee.getCause();
658f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(TestNGRuntimeException.class.equals(cause.getClass())) {
659f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setThrowable(cause.getCause());
660f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
661f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
662f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setThrowable(cause);
663f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
664d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com      testResult.setStatus(ITestResult.FAILURE);
665f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
666f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(Throwable thr) { // covers the non-wrapper exceptions
667f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setThrowable(thr);
668d3c04c36b8f179fd5aa1b53711a5b909cde06d09nalin.makar@gmail.com      testResult.setStatus(ITestResult.FAILURE);
669f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
670f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    finally {
671dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      // Set end time ASAP
672dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      testResult.setEndMillis(System.currentTimeMillis());
673dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin
674bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust      ExpectedExceptionsHolder expectedExceptionClasses
6753b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr          = new ExpectedExceptionsHolder(m_annotationFinder, tm, new RegexpExpectedExceptionsHolder(m_annotationFinder, tm));
676dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      List<ITestResult> results = Lists.<ITestResult>newArrayList(testResult);
67716d23357bbc58d4d394ac7a96b2bb8196cae6bf2Ryan Schmitt      handleInvocationResults(tm, results, expectedExceptionClasses, failureContext);
67889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
679dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      // If this method has a data provider and just failed, memorize the number
680dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      // at which it failed.
6811ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // Note: we're not exactly testing that this method has a data provider, just
6821ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // that it has parameters, so might have to revisit this if bugs get reported
6831ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // for the case where this method has parameters that don't come from a data
6841ed096c7af783713cdeb4a3e9c0c4a02491d65fcCédric Beust      // provider
685dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      if (testResult.getThrowable() != null && parameterValues.length > 0) {
686927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust        tm.addFailedInvocationNumber(parametersIndex);
687dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust      }
688dd84c4f1673772d6b1febb72add6a2ae40f4e4ccCédric Beust
689f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
690f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Increment the invocation count for this method
691f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
692f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      tm.incrementCurrentInvocationCount();
693f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
6947ba4f0edf349cd33491ea94c9ccf88ba9e1fa117Cédric Beust      // Run invokedMethodListeners after updating TestResult
6957ba4f0edf349cd33491ea94c9ccf88ba9e1fa117Cédric Beust      runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult);
6967ba4f0edf349cd33491ea94c9ccf88ba9e1fa117Cédric Beust      runTestListeners(testResult);
697bacea92cd4a97cc839df9533025400c343a4689fCédric Beust
698f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
69945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // Invoke afterMethods only if
70045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // - lastTimeOnly is not set
70145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // - lastTimeOnly is set, and we are reaching the last invocationCount
702f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
70389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      invokeConfigurations(testClass, tm,
70445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          filterConfigurationMethods(tm, afterMethods, false /* beforeMethods */),
705facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust          suite, params, parameterValues,
7063297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust          instance,
707da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust          testResult);
70889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
709f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
71045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // Invoke afterGroups configurations
711f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
712f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeAfterGroupsConfigurations(testClass, tm, groupMethods, suite,
7133297414dee4e2372259dd538dd359e0b65e9d305Cédric Beust          params, instance);
7143b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust
7153b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust      // Reset the test result last. If we do this too early, Reporter.log()
7163b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust      // invocations from listeners will be discarded
7173b368261cd916f9e03a2fcbf168258518d6638a3Cédric Beust      Reporter.setCurrentTestResult(null);
718f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
71994efdf8e6ac7332eadf8bfe5d1fe699caee5d051Cédric Beust
720f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return testResult;
721f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
72289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
723dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin  void collectResults(ITestNGMethod testMethod, Collection<ITestResult> results) {
724dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    for (ITestResult result : results) {
72534ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      // Collect the results
726dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      final int status = result.getStatus();
72734ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      if(ITestResult.SUCCESS == status) {
728dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addPassedTest(testMethod, result);
72934ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
73034ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else if(ITestResult.SKIP == status) {
731dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addSkippedTest(testMethod, result);
73234ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
73334ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else if(ITestResult.FAILURE == status) {
734dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addFailedTest(testMethod, result);
73534ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
73634ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) {
737dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, result);
73834ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
73934ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      else {
74034ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust        assert false : "UNKNOWN STATUS:" + status;
74134ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust      }
74234ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust    }
74334ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust  }
74434ce5b443d17bd8cfeb7fd591755bf50258ddd69Cédric Beust
745f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
74645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * The array of methods contains @BeforeMethods if isBefore if true, @AfterMethods
74745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * otherwise.  This function removes all the methods that should not be run at this
74845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * point because they are either firstTimeOnly or lastTimeOnly and we haven't reached
74945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * the current invocationCount yet
75045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   */
75145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  private ITestNGMethod[] filterConfigurationMethods(ITestNGMethod tm,
75245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      ITestNGMethod[] methods, boolean isBefore)
75345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  {
754ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestNGMethod> result = Lists.newArrayList();
75545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    for (ITestNGMethod m : methods) {
75645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      ConfigurationMethod cm = (ConfigurationMethod) m;
75745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      if (isBefore) {
75845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        if (! cm.isFirstTimeOnly() ||
75945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust            (cm.isFirstTimeOnly() && tm.getCurrentInvocationCount() == 0))
76045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        {
76145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          result.add(m);
76245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        }
76345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      }
76445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      else {
765d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        int current = tm.getCurrentInvocationCount();
766d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        boolean isLast = false;
7672fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // If we have parameters, set the boolean if we are about to run
7682fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // the last invocation
769d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        if (tm.getParameterInvocationCount() > 0) {
770ce11604bda708dbd2c42435e77027d5c360c9fa9Julien Herr          isLast = current == tm.getParameterInvocationCount() * tm.getTotalInvocationCount();
771d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        }
7722fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // If we have invocationCount > 1, set the boolean if we are about to
7732fc881781da9eb64b913650c8bb856d1f97c64cdCédric Beust        // run the last invocation
774ce11604bda708dbd2c42435e77027d5c360c9fa9Julien Herr        else if (tm.getTotalInvocationCount() > 1) {
775ce11604bda708dbd2c42435e77027d5c360c9fa9Julien Herr          isLast = current == tm.getTotalInvocationCount();
776d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        }
777d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        if (! cm.isLastTimeOnly() || (cm.isLastTimeOnly() && isLast)) {
77845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          result.add(m);
77945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        }
78045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      }
78145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    }
78245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust
78345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    return result.toArray(new ITestNGMethod[result.size()]);
78445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  }
78545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust
78645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  /**
787ad662c0a3971e0461a1aaa7580fd3c7e7a114a02Cédric Beust   * invokeTestMethods() eventually converge here to invoke a single @Test method.
788f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
789f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * This method is responsible for actually invoking the method. It decides if the invocation
790f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * must be done:
791f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <ul>
79289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * <li>through an <code>IHookable</code></li>
793f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <li>directly (through reflection)</li>
794f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <li>in a separate thread (in case it needs to timeout)
795f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * </ul>
79689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   *
797f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
798dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin   * This method is also responsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup
799f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * if it is the case for the passed in @Test method.
800f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
801dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin  protected ITestResult invokeTestMethod(Object instance,
802f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             final ITestNGMethod tm,
803f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Object[] parameterValues,
804927a6d8a655520943e3a8a9ea9f09cbfe56f2ae6Cédric Beust                                             int parametersIndex,
805f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             XmlSuite suite,
806f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Map<String, String> params,
807f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestClass testClass,
808f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestNGMethod[] beforeMethods,
809f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestNGMethod[] afterMethods,
8106b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                             ConfigurationGroupMethods groupMethods,
8116b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                             FailureContext failureContext)
812f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
813f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Mark this method with the current thread id
814f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    tm.setId(ThreadUtil.currentThreadInfo());
815f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
816dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    ITestResult result = invokeMethod(instance, tm, parameterValues, parametersIndex, suite, params,
8173b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                                      testClass, beforeMethods, afterMethods, groupMethods,
8183b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                                      failureContext);
819f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
820dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    return result;
821f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
822f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
823f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
824f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Filter all the beforeGroups methods and invoke only those that apply
825f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * to the current test method
826f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
82789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void invokeBeforeGroupsConfigurations(ITestClass testClass,
82889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                ITestNGMethod currentTestMethod,
82989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                ConfigurationGroupMethods groupMethods,
83089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                XmlSuite suite,
83189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                Map<String, String> params,
83289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                Object instance)
833f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
834f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    synchronized(groupMethods) {
835ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust      List<ITestNGMethod> filteredMethods = Lists.newArrayList();
836f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      String[] groups = currentTestMethod.getGroups();
837f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, List<ITestNGMethod>> beforeGroupMap = groupMethods.getBeforeGroupsMap();
83889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
839f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String group : groups) {
840f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        List<ITestNGMethod> methods = beforeGroupMap.get(group);
841f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (methods != null) {
842f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          filteredMethods.addAll(methods);
843f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
844f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
84589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
846f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] beforeMethodsArray = filteredMethods.toArray(new ITestNGMethod[filteredMethods.size()]);
847f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
848f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Invoke the right groups methods
849f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
850f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(beforeMethodsArray.length > 0) {
851f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // don't pass the IClass or the instance as the method may be external
852f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // the invocation must be similar to @BeforeTest/@BeforeSuite
85389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin        invokeConfigurations(null, beforeMethodsArray, suite, params,
854facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust            null, /* no parameter values */
855facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust            null);
856f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
85789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
858f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
859f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Remove them so they don't get run again
860f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
861f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      groupMethods.removeBeforeGroups(groups);
862f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
863f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
864f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
86589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private void invokeAfterGroupsConfigurations(ITestClass testClass,
866f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               ITestNGMethod currentTestMethod,
867f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               ConfigurationGroupMethods groupMethods,
86889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                               XmlSuite suite,
86989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                               Map<String, String> params,
87089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                               Object instance)
871f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
872f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Skip this if the current method doesn't belong to any group
873f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // (only a method that belongs to a group can trigger the invocation
874f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // of afterGroups methods)
8750f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    if (currentTestMethod.getGroups().length == 0) {
8760f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      return;
8770f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    }
87889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
879f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // See if the currentMethod is the last method in any of the groups
880f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // it belongs to
8810f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust    Map<String, String> filteredGroups = Maps.newHashMap();
882f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] groups = currentTestMethod.getGroups();
883f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    synchronized(groupMethods) {
884f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String group : groups) {
885f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (groupMethods.isLastMethodForGroup(group, currentTestMethod)) {
886f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          filteredGroups.put(group, group);
887f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
888f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
88989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
8900f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if(filteredGroups.isEmpty()) {
8910f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        return;
8920f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
89389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
894f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // The list of afterMethods to run
8950f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust      Map<ITestNGMethod, ITestNGMethod> afterMethods = Maps.newHashMap();
89689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
897f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Now filteredGroups contains all the groups for which we need to run the afterGroups
898f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // method.  Find all the methods that correspond to these groups and invoke them.
899f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, List<ITestNGMethod>> map = groupMethods.getAfterGroupsMap();
900f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String g : filteredGroups.values()) {
901f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        List<ITestNGMethod> methods = map.get(g);
902f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Note:  should put them in a map if we want to make sure the same afterGroups
903f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // doesn't get run twice
904f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (methods != null) {
905f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          for (ITestNGMethod m : methods) {
906f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            afterMethods.put(m, m);
907f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
908f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
909f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
91089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
911f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Got our afterMethods, invoke them
912f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] afterMethodsArray = afterMethods.keySet().toArray(new ITestNGMethod[afterMethods.size()]);
913f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // don't pass the IClass or the instance as the method may be external
914f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // the invocation must be similar to @BeforeTest/@BeforeSuite
91589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      invokeConfigurations(null, afterMethodsArray, suite, params,
916facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust          null, /* no parameter values */
917facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust          null);
918f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
919f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Remove the groups so they don't get run again
92089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      groupMethods.removeAfterGroups(filteredGroups.keySet());
921f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
922f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
923f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
924f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private Object[] getParametersFromIndex(Iterator<Object[]> parametersValues, int index) {
925f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while (parametersValues.hasNext()) {
926f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object[] parameters = parametersValues.next();
927f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
928f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (index == 0) {
929f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        return parameters;
930f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
931f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      index--;
932f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
933f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return null;
934f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
93589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
9366293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin  int retryFailed(Object instance,
937f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           final ITestNGMethod tm,
938f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           XmlSuite suite,
939f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestClass testClass,
940f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestNGMethod[] beforeMethods,
941f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestNGMethod[] afterMethods,
942f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ConfigurationGroupMethods groupMethods,
943f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           List<ITestResult> result,
944f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           int failureCount,
945bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust                           ExpectedExceptionsHolder expectedExceptionHolder,
946f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestContext testContext,
947f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           Map<String, String> parameters,
948f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           int parametersIndex) {
9496b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    final FailureContext failure = new FailureContext();
9506b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    failure.count = failureCount;
95192206009b23ecbbf29e5a0d20f6b095a552afcb8Cédric Beust    do {
9526c40ac103c04fac38274dafc077d55df12e9d8d7Krishnan Mahadevan      failure.instances = Lists.newArrayList ();
9530f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust      Map<String, String> allParameters = Maps.newHashMap();
954f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      /**
955f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       * TODO: This recreates all the parameters every time when we only need
956f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       * one specific set. Should optimize it by only recreating the set needed.
957f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       */
958db04b1679d3367e54e61d7e6f8c225354e90081cCédric Beust      ParameterBag bag = createParameters(tm, parameters,
959c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin          allParameters, suite, testContext, null /* fedInstance */);
960c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust      Object[] parameterValues =
961c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust          getParametersFromIndex(bag.parameterHolder.parameters, parametersIndex);
962f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
9636b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin      result.add(invokeMethod(instance, tm, parameterValues, parametersIndex, suite,
9646b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin          allParameters, testClass, beforeMethods, afterMethods, groupMethods, failure));
965f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
9666b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    while (!failure.instances.isEmpty());
9676b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    return failure.count;
968f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
96989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
970db04b1679d3367e54e61d7e6f8c225354e90081cCédric Beust  private ParameterBag createParameters(ITestNGMethod testMethod,
971f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        Map<String, String> parameters,
972f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        Map<String, String> allParameterNames,
973f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        XmlSuite suite,
9748b9443a6ada20a1e9f3852b715f3e789a0f8d490Cédric Beust                                        ITestContext testContext,
975c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin                                        Object fedInstance)
9768778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust  {
9778778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    Object instance;
9788778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    if (fedInstance != null) {
9798778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust      instance = fedInstance;
9808778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    }
9818778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    else {
9827955b9d255852b83f9c96277dece4d6807cb69f5Cédric Beust      instance = testMethod.getInstance();
9838778efa4afcae00d4f8c645cc7ac5fcb32a71dd3Cédric Beust    }
98489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
985c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    ParameterBag bag = handleParameters(testMethod,
986c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin        instance, allParameterNames, parameters, null, suite, testContext, fedInstance, null);
987f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
988f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return bag;
989f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
99089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
991f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
992eddb4a9423c14fee808a30e92ad77a16e88b320enullin   * Invoke all the test methods. Note the plural: the method passed in
993f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * parameter might be invoked several times if the test class it belongs
994f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * to has more than one instance (i.e., if an @Factory method has been
995f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * declared somewhere that returns several instances of this TestClass).
996f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * If no @Factory method was specified, testMethod will only be invoked
997f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * once.
998f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
999f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Note that this method also takes care of invoking the beforeTestMethod
1000f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * and afterTestMethod, if any.
100189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   *
100289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * Note (alex): this method can be refactored to use a SingleTestMethodWorker that
100389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * directly invokes
10044dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin   * {@link #invokeTestMethod(Object, ITestNGMethod, Object[], int, XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods, FailureContext)}
1005f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * and this would simplify the implementation (see how DataTestMethodWorker is used)
1006f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1007423a12bc8666e263237e0ce8abcfb096eb72b55aCédric Beust  @Override
1008f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public List<ITestResult> invokeTestMethods(ITestNGMethod testMethod,
1009f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             XmlSuite suite,
1010e54cfbea931bc5370eeec8c03b92f6598577a5c4Cédric Beust                                             Map<String, String> testParameters,
1011f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ConfigurationGroupMethods groupMethods,
10126293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin                                             Object instance,
1013f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestContext testContext)
1014f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1015f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Potential bug here if the test method was declared on a parent class
101689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    assert null != testMethod.getTestClass()
1017dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin        : "COULDN'T FIND TESTCLASS FOR " + testMethod.getRealClass();
101889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1019eddb4a9423c14fee808a30e92ad77a16e88b320enullin    if (!MethodHelper.isEnabled(testMethod.getMethod(), m_annotationFinder)) {
1020dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      // return if the method is not enabled. No need to do any more calculations
1021dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      return Collections.emptyList();
1022eddb4a9423c14fee808a30e92ad77a16e88b320enullin    }
1023eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1024a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    // By the time this testMethod to be invoked,
1025a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    // all dependencies should be already run or we need to skip this method,
1026a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    // so invocation count should not affect dependencies check
1027a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final String okToProceed = checkDependencies(testMethod, testContext.getAllTestMethods());
10284bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10294bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    if (okToProceed != null) {
10304bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      //
10314bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      // Not okToProceed. Test is being skipped
10324bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      //
1033a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin      ITestResult result = registerSkippedTestResult(testMethod, null, System.currentTimeMillis(),
1034a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin          new Throwable(okToProceed));
1035a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin      m_notifier.addSkippedTest(testMethod, result);
1036a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin      return Collections.singletonList(result);
10374bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    }
10384bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10394bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10404bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    final Map<String, String> parameters =
10414bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin        testMethod.findMethodParameters(testContext.getCurrentXmlTest());
10424bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
10434bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    // For invocationCount > 1 and threadPoolSize > 1 run this method in its own pool thread.
10444bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    if (testMethod.getInvocationCount() > 1 && testMethod.getThreadPoolSize() > 1) {
10454bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      return invokePooledTestMethods(testMethod, suite, parameters, groupMethods, testContext);
10464bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin    }
10474bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin
1048331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust    long timeOutInvocationCount = testMethod.getInvocationTimeOut();
1049eddb4a9423c14fee808a30e92ad77a16e88b320enullin    //FIXME: Is this correct?
1050331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust    boolean onlyOne = testMethod.getThreadPoolSize() > 1 ||
1051331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust      timeOutInvocationCount > 0;
105289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1053331487029766f0e6623b8cd8078ec75aaec7de75Cédric Beust    int invocationCount = onlyOne ? 1 : testMethod.getInvocationCount();
1054f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
105589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    ExpectedExceptionsHolder expectedExceptionHolder =
10563b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr        new ExpectedExceptionsHolder(m_annotationFinder, testMethod,
10573b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                                     new RegexpExpectedExceptionsHolder(m_annotationFinder, testMethod));
1058a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final ITestClass testClass= testMethod.getTestClass();
1059a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final List<ITestResult> result = Lists.newArrayList();
10606b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    final FailureContext failure = new FailureContext();
1061a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods(), CAN_RUN_FROM_CLASS);
1062a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin    final ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods(), CAN_RUN_FROM_CLASS);
1063f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while(invocationCount-- > 0) {
10644bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin      if(false) {
10654bad7e615c0a2e18218160a98521a8d015046a1dVladislav Rassokhin        // Prevent code formatting
1066eddb4a9423c14fee808a30e92ad77a16e88b320enullin      }
1067eddb4a9423c14fee808a30e92ad77a16e88b320enullin      //
1068eddb4a9423c14fee808a30e92ad77a16e88b320enullin      // No threads, regular invocation
1069eddb4a9423c14fee808a30e92ad77a16e88b320enullin      //
1070eddb4a9423c14fee808a30e92ad77a16e88b320enullin      else {
1071a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin        // Used in catch statement
1072a85a2ac54f23fc8a01c2d59a56997f7eb7d40cdbVladislav Rassokhin        long start = System.currentTimeMillis();
1073eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1074eddb4a9423c14fee808a30e92ad77a16e88b320enullin        Map<String, String> allParameterNames = Maps.newHashMap();
1075db04b1679d3367e54e61d7e6f8c225354e90081cCédric Beust        ParameterBag bag = createParameters(testMethod,
1076c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin            parameters, allParameterNames, suite, testContext, instance);
1077eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1078eddb4a9423c14fee808a30e92ad77a16e88b320enullin        if (bag.hasErrors()) {
10794dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          final ITestResult tr = bag.errorResult;
10804dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          tr.setStatus(ITestResult.SKIP);
10814dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          runTestListeners(tr);
10824dd8f4768197b043fdb3876ec203e8618c69015bVladislav Rassokhin          m_notifier.addSkippedTest(testMethod, tr);
1083061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust          result.add(tr);
1084eddb4a9423c14fee808a30e92ad77a16e88b320enullin          continue;
1085eddb4a9423c14fee808a30e92ad77a16e88b320enullin        }
1086eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1087eddb4a9423c14fee808a30e92ad77a16e88b320enullin        Iterator<Object[]> allParameterValues = bag.parameterHolder.parameters;
1088eddb4a9423c14fee808a30e92ad77a16e88b320enullin        int parametersIndex = 0;
1089eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1090eddb4a9423c14fee808a30e92ad77a16e88b320enullin        try {
1091eddb4a9423c14fee808a30e92ad77a16e88b320enullin          List<TestMethodWithDataProviderMethodWorker> workers = Lists.newArrayList();
1092eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1093eddb4a9423c14fee808a30e92ad77a16e88b320enullin          if (bag.parameterHolder.origin == ParameterOrigin.ORIGIN_DATA_PROVIDER &&
1094eddb4a9423c14fee808a30e92ad77a16e88b320enullin              bag.parameterHolder.dataProviderHolder.annotation.isParallel()) {
1095eddb4a9423c14fee808a30e92ad77a16e88b320enullin            while (allParameterValues.hasNext()) {
1096eddb4a9423c14fee808a30e92ad77a16e88b320enullin              Object[] parameterValues = injectParameters(allParameterValues.next(),
1097eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  testMethod.getMethod(), testContext, null /* test result */);
1098eddb4a9423c14fee808a30e92ad77a16e88b320enullin              TestMethodWithDataProviderMethodWorker w =
1099eddb4a9423c14fee808a30e92ad77a16e88b320enullin                new TestMethodWithDataProviderMethodWorker(this,
1100eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    testMethod, parametersIndex,
11016293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin                    parameterValues, instance, suite, parameters, testClass,
1102eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    beforeMethods, afterMethods, groupMethods,
1103eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    expectedExceptionHolder, testContext, m_skipFailedInvocationCounts,
11046b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    invocationCount, failure.count, m_notifier);
1105eddb4a9423c14fee808a30e92ad77a16e88b320enullin              workers.add(w);
1106eddb4a9423c14fee808a30e92ad77a16e88b320enullin              // testng387: increment the param index in the bag.
1107eddb4a9423c14fee808a30e92ad77a16e88b320enullin              parametersIndex++;
1108eddb4a9423c14fee808a30e92ad77a16e88b320enullin            }
11099eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            PoolService<List<ITestResult>> ps =
111010c223b7aa6bf34778079bb5ee1a494c83cd1239Ryan Schmitt                    new PoolService<>(suite.getDataProviderThreadCount());
11119eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            List<List<ITestResult>> r = ps.submitTasksAndWait(workers);
11129eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            for (List<ITestResult> l2 : r) {
11139eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust              result.addAll(l2);
11149eed55ba5fb688764b554f413f6d2ce2619d4ddcCédric Beust            }
1115eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1116eddb4a9423c14fee808a30e92ad77a16e88b320enullin          } else {
1117eddb4a9423c14fee808a30e92ad77a16e88b320enullin            while (allParameterValues.hasNext()) {
1118eddb4a9423c14fee808a30e92ad77a16e88b320enullin              Object[] parameterValues = injectParameters(allParameterValues.next(),
1119eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  testMethod.getMethod(), testContext, null /* test result */);
1120eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1121eddb4a9423c14fee808a30e92ad77a16e88b320enullin              List<ITestResult> tmpResults = Lists.newArrayList();
1122eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1123eddb4a9423c14fee808a30e92ad77a16e88b320enullin              try {
1124dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                tmpResults.add(invokeTestMethod(instance,
1125dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    testMethod,
1126dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    parameterValues,
1127dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    parametersIndex,
1128dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    suite,
1129dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    parameters,
1130dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    testClass,
1131dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    beforeMethods,
1132dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin                    afterMethods,
11336b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    groupMethods, failure));
1134eddb4a9423c14fee808a30e92ad77a16e88b320enullin              }
1135eddb4a9423c14fee808a30e92ad77a16e88b320enullin              finally {
11366b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                if (failure.instances.isEmpty()) {
1137eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  result.addAll(tmpResults);
1138eddb4a9423c14fee808a30e92ad77a16e88b320enullin                } else {
11396b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                  for (Object failedInstance : failure.instances) {
1140eddb4a9423c14fee808a30e92ad77a16e88b320enullin                    List<ITestResult> retryResults = Lists.newArrayList();
1141eddb4a9423c14fee808a30e92ad77a16e88b320enullin
11426b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    failure.count = retryFailed(
11436b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                            failedInstance, testMethod, suite, testClass, beforeMethods,
1144eddb4a9423c14fee808a30e92ad77a16e88b320enullin                     afterMethods, groupMethods, retryResults,
11456b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                     failure.count, expectedExceptionHolder,
1146eddb4a9423c14fee808a30e92ad77a16e88b320enullin                     testContext, parameters, parametersIndex);
1147eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  result.addAll(retryResults);
1148eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  }
1149eddb4a9423c14fee808a30e92ad77a16e88b320enullin                }
1150eddb4a9423c14fee808a30e92ad77a16e88b320enullin
1151eddb4a9423c14fee808a30e92ad77a16e88b320enullin                //
1152eddb4a9423c14fee808a30e92ad77a16e88b320enullin                // If we have a failure, skip all the
1153eddb4a9423c14fee808a30e92ad77a16e88b320enullin                // other invocationCounts
1154eddb4a9423c14fee808a30e92ad77a16e88b320enullin                //
11556b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                if (failure.count > 0
1156eddb4a9423c14fee808a30e92ad77a16e88b320enullin                      && (m_skipFailedInvocationCounts
1157eddb4a9423c14fee808a30e92ad77a16e88b320enullin                            || testMethod.skipFailedInvocations())) {
1158eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  while (invocationCount-- > 0) {
11596b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                    result.add(registerSkippedTestResult(testMethod, instance, System.currentTimeMillis(), null));
1160eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  }
1161eddb4a9423c14fee808a30e92ad77a16e88b320enullin                  break;
1162eddb4a9423c14fee808a30e92ad77a16e88b320enullin                }
1163eddb4a9423c14fee808a30e92ad77a16e88b320enullin              }// end finally
1164eddb4a9423c14fee808a30e92ad77a16e88b320enullin              parametersIndex++;
1165eddb4a9423c14fee808a30e92ad77a16e88b320enullin            }
1166eddb4a9423c14fee808a30e92ad77a16e88b320enullin          }
1167eddb4a9423c14fee808a30e92ad77a16e88b320enullin        }
1168eddb4a9423c14fee808a30e92ad77a16e88b320enullin        catch (Throwable cause) {
1169eddb4a9423c14fee808a30e92ad77a16e88b320enullin          ITestResult r =
1170eddb4a9423c14fee808a30e92ad77a16e88b320enullin              new TestResult(testMethod.getTestClass(),
11716293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin                instance,
1172eddb4a9423c14fee808a30e92ad77a16e88b320enullin                testMethod,
1173eddb4a9423c14fee808a30e92ad77a16e88b320enullin                cause,
1174eddb4a9423c14fee808a30e92ad77a16e88b320enullin                start,
11756f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                System.currentTimeMillis(),
11766f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen                m_testContext);
1177eddb4a9423c14fee808a30e92ad77a16e88b320enullin            r.setStatus(TestResult.FAILURE);
1178eddb4a9423c14fee808a30e92ad77a16e88b320enullin            result.add(r);
1179eddb4a9423c14fee808a30e92ad77a16e88b320enullin            runTestListeners(r);
1180eddb4a9423c14fee808a30e92ad77a16e88b320enullin            m_notifier.addFailedTest(testMethod, r);
1181eddb4a9423c14fee808a30e92ad77a16e88b320enullin        } // catch
1182f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1183f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
118489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1185f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
118689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1187f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  } // invokeTestMethod
1188f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1189252c45802df7624a4fafbce810e05d22048f437bCédric Beust  private ITestResult registerSkippedTestResult(ITestNGMethod testMethod, Object instance,
1190fe08327fabe1654f4f509edcf28c3296ad054fc5Cédric Beust      long start, Throwable throwable) {
119189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    ITestResult result =
1192252c45802df7624a4fafbce810e05d22048f437bCédric Beust      new TestResult(testMethod.getTestClass(),
1193252c45802df7624a4fafbce810e05d22048f437bCédric Beust        instance,
1194252c45802df7624a4fafbce810e05d22048f437bCédric Beust        testMethod,
1195fe08327fabe1654f4f509edcf28c3296ad054fc5Cédric Beust        throwable,
1196252c45802df7624a4fafbce810e05d22048f437bCédric Beust        start,
11976f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen        System.currentTimeMillis(),
11986f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen        m_testContext);
1199252c45802df7624a4fafbce810e05d22048f437bCédric Beust    result.setStatus(TestResult.SKIP);
1200252c45802df7624a4fafbce810e05d22048f437bCédric Beust    runTestListeners(result);
1201252c45802df7624a4fafbce810e05d22048f437bCédric Beust
1202252c45802df7624a4fafbce810e05d22048f437bCédric Beust    return result;
1203252c45802df7624a4fafbce810e05d22048f437bCédric Beust  }
1204252c45802df7624a4fafbce810e05d22048f437bCédric Beust
120528e899a6c1620c8d07cb04a92f96658550e4af16nullin  /**
120628e899a6c1620c8d07cb04a92f96658550e4af16nullin   * Gets an array of parameter values returned by data provider or the ones that
120728e899a6c1620c8d07cb04a92f96658550e4af16nullin   * are injected based on parameter type. The method also checks for {@code NoInjection}
120828e899a6c1620c8d07cb04a92f96658550e4af16nullin   * annotation
120928e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param parameterValues parameter values from a data provider
121028e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param method method to be invoked
121128e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param context test context
121228e899a6c1620c8d07cb04a92f96658550e4af16nullin   * @param testResult test result
121328e899a6c1620c8d07cb04a92f96658550e4af16nullin   */
12141e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust  private Object[] injectParameters(Object[] parameterValues, Method method,
121528e899a6c1620c8d07cb04a92f96658550e4af16nullin      ITestContext context, ITestResult testResult)
121628e899a6c1620c8d07cb04a92f96658550e4af16nullin    throws TestNGException {
12171e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    List<Object> vResult = Lists.newArrayList();
12181e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    int i = 0;
121928e899a6c1620c8d07cb04a92f96658550e4af16nullin    int numValues = parameterValues.length;
122028e899a6c1620c8d07cb04a92f96658550e4af16nullin    int numParams = method.getParameterTypes().length;
122128e899a6c1620c8d07cb04a92f96658550e4af16nullin
12228211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust    if (numValues > numParams && ! method.isVarArgs()) {
12238211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust      throw new TestNGException("The data provider is trying to pass " + numValues
12248211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          + " parameters but the method "
12258211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          + method.getDeclaringClass().getName() + "#" + method.getName()
12268211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          + " takes " + numParams);
122728e899a6c1620c8d07cb04a92f96658550e4af16nullin    }
122828e899a6c1620c8d07cb04a92f96658550e4af16nullin
122928e899a6c1620c8d07cb04a92f96658550e4af16nullin    // beyond this, numValues <= numParams
12301e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    for (Class<?> cls : method.getParameterTypes()) {
1231aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      Annotation[] annotations = method.getParameterAnnotations()[i];
1232aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      boolean noInjection = false;
1233aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      for (Annotation a : annotations) {
1234aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust        if (a instanceof NoInjection) {
1235aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust          noInjection = true;
1236aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust          break;
1237aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust        }
1238aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      }
12391e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust      Object injected = Parameters.getInjectedParameter(cls, method, context, testResult);
1240aba3ac2f9fc3e370339b911598f62c7ffb6752aaCédric Beust      if (injected != null && ! noInjection) {
12411e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust        vResult.add(injected);
12421e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust      } else {
124328e899a6c1620c8d07cb04a92f96658550e4af16nullin        try {
1244e7405399f36ed7b9383424f5175980fe2698a403Cédric Beust          if (method.isVarArgs()) vResult.add(parameterValues);
1245e7405399f36ed7b9383424f5175980fe2698a403Cédric Beust          else vResult.add(parameterValues[i++]);
124628e899a6c1620c8d07cb04a92f96658550e4af16nullin        } catch (ArrayIndexOutOfBoundsException ex) {
12478211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust          throw new TestNGException("The data provider is trying to pass " + numValues
12488211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + " parameters but the method "
12498211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + method.getDeclaringClass().getName() + "#" + method.getName()
12508211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + " takes " + numParams
12518211ccc6e66d114d50826b44f06b8e1d42f7811aCédric Beust              + " and TestNG is unable in inject a suitable object", ex);
125228e899a6c1620c8d07cb04a92f96658550e4af16nullin        }
12531e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust      }
12541e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    }
12551e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust    return vResult.toArray(new Object[vResult.size()]);
12561e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust  }
12571e15cc3fecfaea9149afe8124d2fd95f4356c193Cédric Beust
1258f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ParameterBag handleParameters(ITestNGMethod testMethod,
1259f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object instance,
1260f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> allParameterNames,
1261f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> parameters,
1262facba56b6ead0cb76ba78ac1cfeae1bbe851ad9cCédric Beust      Object[] parameterValues,
1263f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlSuite suite,
12648b9443a6ada20a1e9f3852b715f3e789a0f8d490Cédric Beust      ITestContext testContext,
1265da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust      Object fedInstance,
1266da4f4527ccc23d7a7d777627332b6c7332266a16Cédric Beust      ITestResult testResult)
1267f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1268f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    try {
1269c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust      return new ParameterBag(
1270c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust          Parameters.handleParameters(testMethod,
127189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin            allParameterNames,
127289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin            instance,
127366aec6c16d8782f01933c0b45e1c5b3976e04dd6Cédric Beust            new Parameters.MethodParameters(parameters,
127466aec6c16d8782f01933c0b45e1c5b3976e04dd6Cédric Beust                testMethod.findMethodParameters(testContext.getCurrentXmlTest()),
127566aec6c16d8782f01933c0b45e1c5b3976e04dd6Cédric Beust                parameterValues,
127689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                testMethod.getMethod(), testContext, testResult),
127789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin            suite,
1278c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust            m_annotationFinder,
1279c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin            fedInstance));
1280f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1281061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust//    catch(TestNGException ex) {
1282061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust//      throw ex;
1283061a9ae01a09d45e337c69b64d1b5a81ebee3868Cédric Beust//    }
1284f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(Throwable cause) {
1285c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      return new ParameterBag(
1286f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          new TestResult(
128789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              testMethod.getTestClass(),
128889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              instance,
128989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              testMethod,
129089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin              cause,
1291f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              System.currentTimeMillis(),
12926f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen              System.currentTimeMillis(),
12936f53a2551bab7c2f5a85c6f5ede755512e490a4bBrandon Pedersen              m_testContext));
1294f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1295f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
129689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1297f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
129889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin   * Invokes a method that has a specified threadPoolSize.
1299f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
130089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private List<ITestResult> invokePooledTestMethods(ITestNGMethod testMethod,
130189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                    XmlSuite suite,
130289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                    Map<String, String> parameters,
1303f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                    ConfigurationGroupMethods groupMethods,
130489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin                                                    ITestContext testContext)
1305f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1306f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1307f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Create the workers
1308f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1309f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    List<IWorker<ITestNGMethod>> workers = Lists.newArrayList();
131089fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
13119d65d102f64e4fe2e629de8e87c8b92379a9349eCédric Beust    // Create one worker per invocationCount
1312f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (int i = 0; i < testMethod.getInvocationCount(); i++) {
1313f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // we use clones for reporting purposes
1314f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod clonedMethod= testMethod.clone();
1315f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      clonedMethod.setInvocationCount(1);
1316f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      clonedMethod.setThreadPoolSize(1);
1317f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1318eb2b9ac857aad415986677a51513d47e91eb7c8dCédric Beust      MethodInstance mi = new MethodInstance(clonedMethod);
1319f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      workers.add(new SingleTestMethodWorker(this,
1320f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          mi,
132189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin          suite,
1322f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          parameters,
1323f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testContext));
1324f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1325f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
13263b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr    return runWorkers(testMethod, workers, testMethod.getThreadPoolSize(), groupMethods, suite,
13273b2881b877fe7515d1f774f2f06755ceb56a09e7Julien Herr                      parameters);
1328f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
132989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
13306b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  static class FailureContext {
13316b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    int count = 0;
13326b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    List<Object> instances = Lists.newArrayList();
13336b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  }
13346b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin
13356b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  void handleInvocationResults(ITestNGMethod testMethod,
13366b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                               List<ITestResult> result,
13376b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                               ExpectedExceptionsHolder expectedExceptionsHolder,
13386b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                               FailureContext failure)
13396216d78ae0757b7d57aa6e94cc041447d610724dCédric Beust  {
1340f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1341f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Go through all the results and create a TestResult for each of them
1342f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1343ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestResult> resultsToRetry = Lists.newArrayList();
1344f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
13456293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin    for (ITestResult testResult : result) {
1346f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Throwable ite= testResult.getThrowable();
1347f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      int status= testResult.getStatus();
1348f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
13496b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin      boolean handled = false;
13506b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin
1351f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Exception thrown?
13524c02d89d66fe0319dd20083e705addd6b5f3e8cdCédric Beust      if (ite != null) {
1353f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1354f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        //  Invocation caused an exception, see if the method was annotated with @ExpectedException
1355f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr        if (expectedExceptionsHolder != null) {
1356cda168c708e5d841b5cd0138b93d45f75b22178eJulien Herr          if (expectedExceptionsHolder.isExpectedException(ite)) {
1357bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust            testResult.setStatus(ITestResult.SUCCESS);
1358cda168c708e5d841b5cd0138b93d45f75b22178eJulien Herr            status = ITestResult.SUCCESS;
1359cda168c708e5d841b5cd0138b93d45f75b22178eJulien Herr          } else {
1360f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr            if (isSkipExceptionAndSkip(ite)){
1361f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr              status = ITestResult.SKIP;
1362f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr            } else {
1363f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr              testResult.setThrowable(expectedExceptionsHolder.wrongException(ite));
1364f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr              status = ITestResult.FAILURE;
1365f594497ff6fd02ece89f19975bb074d5ef87261bJulien Herr            }
1366bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust          }
13672343cba1dccc30a50322215da78f14179e2a0271Cédric Beust        } else {
13686b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin          handleException(ite, testMethod, testResult, failure.count++);
13696b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin          handled = true;
1370e919e3dd5edc2dd81296a00446211092f25f54f7Vladislav Rassokhin          status = testResult.getStatus();
1371f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1372f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1373f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1374f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // No exception thrown, make sure we weren't expecting one
1375bfb18c26a3435a04aab4c2f573c03c8664b3b44bCédric Beust      else if(status != ITestResult.SKIP && expectedExceptionsHolder != null) {
1376c50c280b710dc2a33f76f24382242d07e74a268aJulien Herr        TestException exception = expectedExceptionsHolder.noException(testMethod);
1377c55504f189ef27cef6a662084c9353daec31afc9Julien Herr        if (exception != null) {
1378c55504f189ef27cef6a662084c9353daec31afc9Julien Herr          testResult.setThrowable(exception);
1379f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          status= ITestResult.FAILURE;
1380f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1381f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1382f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1383d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      IRetryAnalyzer retryAnalyzer = testMethod.getRetryAnalyzer();
1384d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      boolean willRetry = retryAnalyzer != null && status == ITestResult.FAILURE && failure.instances != null && retryAnalyzer.retry(testResult);
1385f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1386d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      if (willRetry) {
1387d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        resultsToRetry.add(testResult);
138816d23357bbc58d4d394ac7a96b2bb8196cae6bf2Ryan Schmitt        failure.count++;
1389d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        failure.instances.add(testResult.getInstance());
1390d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        testResult.setStatus(ITestResult.SKIP);
1391d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt      } else {
1392d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        testResult.setStatus(status);
1393d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt        if (status == ITestResult.FAILURE && !handled) {
1394d1490f6989c77952b3b5056b5e03d0a883cdb2b7Ryan Schmitt          handleException(ite, testMethod, testResult, failure.count++);
1395f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
139689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      }
139716d23357bbc58d4d394ac7a96b2bb8196cae6bf2Ryan Schmitt      collectResults(testMethod, Collections.singleton(testResult));
1398f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // for results
139989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
14006b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin    removeResultsToRetryFromResult(resultsToRetry, result, failure);
1401f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
140289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
14036671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin  private boolean isSkipExceptionAndSkip(Throwable ite) {
14046671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin    return SkipException.class.isAssignableFrom(ite.getClass()) && ((SkipException) ite).isSkip();
14056671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin  }
1406c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin
14076b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin  private void removeResultsToRetryFromResult(List<ITestResult> resultsToRetry,
14086b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin                                              List<ITestResult> result, FailureContext failure) {
1409f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (resultsToRetry != null) {
1410f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (ITestResult res : resultsToRetry) {
1411f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        result.remove(res);
14126b47dc8954e2ffbb351cb1c72523af24bfc96ef1Vladislav Rassokhin        failure.count--;
1413f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1414f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1415f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
141689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1417f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1418f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * To reduce thread contention and also to correctly handle thread-confinement
1419f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * this method invokes the @BeforeGroups and @AfterGroups corresponding to the current @Test method.
1420f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
142189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin  private List<ITestResult> runWorkers(ITestNGMethod testMethod,
1422c4cadec5fb52419e211120aa93b6118a4ab756ecCédric Beust      List<IWorker<ITestNGMethod>> workers,
142389fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      int threadPoolSize,
142489fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      ConfigurationGroupMethods groupMethods,
142589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      XmlSuite suite,
1426f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> parameters)
1427f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
142889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin    // Invoke @BeforeGroups on the original method (reduce thread contention,
1429c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust    // and also solve thread confinement)
1430f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ITestClass testClass= testMethod.getTestClass();
1431f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Object[] instances = testClass.getInstances(true);
1432f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(Object instance: instances) {
1433f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeBeforeGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance);
1434f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
143589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
143689fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1437f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    long maxTimeOut= -1; // 10 seconds
1438f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1439f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    for(IWorker<ITestNGMethod> tmw : workers) {
1440f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      long mt= tmw.getTimeOut();
1441f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(mt > maxTimeOut) {
1442f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        maxTimeOut= mt;
1443f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1444f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
144589fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1446f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ThreadUtil.execute(workers, threadPoolSize, maxTimeOut, true);
1447f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1448f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1449f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Collect all the TestResults
1450f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1451ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestResult> result = Lists.newArrayList();
1452f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin    for (IWorker<ITestNGMethod> tmw : workers) {
1453f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      if (tmw instanceof TestMethodWorker) {
1454f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin        result.addAll(((TestMethodWorker)tmw).getTestResults());
1455f035a01bd8ac47425984d6b9e07a733f3abb3c37nullin      }
1456f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
145789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1458f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(Object instance: instances) {
1459f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeAfterGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance);
1460f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
146189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1462f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1463f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1464f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1465f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1466e934f66fb4fb247ebf5fec45770bc6820fbba29anullin   * Checks to see of the test method has certain dependencies that prevents
1467e934f66fb4fb247ebf5fec45770bc6820fbba29anullin   * TestNG from executing it
1468e934f66fb4fb247ebf5fec45770bc6820fbba29anullin   * @param testMethod test method being checked for
1469627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin   * @return error message or null if dependencies have been run successfully
1470f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1471627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin  private String checkDependencies(ITestNGMethod testMethod,
1472627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin                                   ITestNGMethod[] allTestMethods)
1473f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1474e934f66fb4fb247ebf5fec45770bc6820fbba29anullin    // If this method is marked alwaysRun, no need to check for its dependencies
1475f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (testMethod.isAlwaysRun()) {
1476627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      return null;
1477f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
147889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1479f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Any missing group?
14800f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    if (testMethod.getMissingGroup() != null
1481627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        && !testMethod.ignoreMissingDependencies()) {
1482627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      return "Method " + testMethod + " depends on nonexistent group \"" + testMethod.getMissingGroup() + "\"";
1483f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1484f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1485f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If this method depends on groups, collect all the methods that
1486f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // belong to these groups and make sure they have been run successfully
1487627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    final String[] groups = testMethod.getGroupsDependedUpon();
1488627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    if (null != groups && groups.length > 0) {
1489f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Get all the methods that belong to the group depended upon
1490627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      for (String element : groups) {
149189fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin        ITestNGMethod[] methods =
1492627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin            MethodGroupsHelper.findMethodsThatBelongToGroup(testMethod,
1493627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin                m_testContext.getAllTestMethods(),
1494627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin                element);
1495627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        if (methods.length == 0 && !testMethod.ignoreMissingDependencies()) {
1496627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          // Group is missing
1497627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          return "Method " + testMethod + " depends on nonexistent group \"" + element + "\"";
1498627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        }
1499627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        if (!haveBeenRunSuccessfully(testMethod, methods)) {
1500627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          return "Method " + testMethod +
1501627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin              " depends on not successfully finished methods in group \"" + element + "\"";
1502627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        }
1503f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1504f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // depends on groups
1505f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1506f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If this method depends on other methods, make sure all these other
1507f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // methods have been run successfully
1508627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    if (dependsOnMethods(testMethod)) {
150989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin      ITestNGMethod[] methods =
1510627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin          MethodHelper.findDependedUponMethods(testMethod, allTestMethods);
1511f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1512627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      if (!haveBeenRunSuccessfully(testMethod, methods)) {
1513627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin        return "Method " + testMethod + " depends on not successfully finished methods";
1514627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin      }
1515f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1516f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1517627859518cc71395c0cbaeebc573d8171fa855b5Vladislav Rassokhin    return null;
1518f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1519f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1520f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1521bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust   * @return the test results that apply to one of the instances of the testMethod.
1522bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust   */
1523bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  private Set<ITestResult> keepSameInstances(ITestNGMethod method, Set<ITestResult> results) {
1524bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    Set<ITestResult> result = Sets.newHashSet();
1525bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    for (ITestResult r : results) {
15266293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin      final Object o = method.getInstance();
15279cb7e93d4f995f0003b27a1f28dc9d939b9b8a36Cédric Beust        // Keep this instance if 1) It's on a different class or 2) It's on the same class
15289cb7e93d4f995f0003b27a1f28dc9d939b9b8a36Cédric Beust        // and on the same instance
152960916e4ddae15723de42347024800d514b85de09Cédric Beust        Object instance = r.getInstance() != null
15306293b3b61db2fc41ca5ab936fea07c81cd1cfcf1Vladislav Rassokhin            ? r.getInstance() : r.getMethod().getInstance();
153160916e4ddae15723de42347024800d514b85de09Cédric Beust        if (r.getTestClass() != method.getTestClass() || instance == o) result.add(r);
1532bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    }
1533bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust    return result;
1534bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  }
1535bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust
1536bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  /**
1537f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if all the methods have been run successfully
1538f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1539bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust  private boolean haveBeenRunSuccessfully(ITestNGMethod testMethod, ITestNGMethod[] methods) {
1540f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Make sure the method has been run successfully
15410f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    for (ITestNGMethod method : methods) {
1542bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust      Set<ITestResult> results = keepSameInstances(testMethod, m_notifier.getPassedTests(method));
154360916e4ddae15723de42347024800d514b85de09Cédric Beust      Set<ITestResult> failedAndSkippedMethods = Sets.newHashSet();
154460916e4ddae15723de42347024800d514b85de09Cédric Beust      failedAndSkippedMethods.addAll(m_notifier.getFailedTests(method));
154560916e4ddae15723de42347024800d514b85de09Cédric Beust      failedAndSkippedMethods.addAll(m_notifier.getSkippedTests(method));
154660916e4ddae15723de42347024800d514b85de09Cédric Beust      Set<ITestResult> failedresults = keepSameInstances(testMethod, failedAndSkippedMethods);
154789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1548bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust      // If failed results were returned on the same instance, then these tests didn't pass
15490f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if (failedresults != null && failedresults.size() > 0) {
15500f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        return false;
15510f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
155289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1553f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (ITestResult result : results) {
1554f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(!result.isSuccess()) {
1555f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          return false;
1556f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1557f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1558f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1559f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1560f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return true;
1561f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1562f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
156310a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//  private boolean containsInstance(Set<ITestResult> failedresults, Object[] instances) {
156410a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//    for (ITestResult tr : failedresults) {
156510a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//      for (Object o : instances) {
156610a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//        if (o == tr.getInstance()) {
156710a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//          return true;
156810a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//        }
156910a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//      }
157010a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//    }
157110a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//    return false;
157210a202a9e96a8067720d9e2a301ee6b67f5df5edCédric Beust//  }
1573bcb654d600d516d1bfce826220fef65e7d262e33Cédric Beust
1574f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1575f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * An exception was thrown by the test, determine if this method
1576f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * should be marked as a failure or as failure_but_within_successPercentage
1577f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1578f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void handleException(Throwable throwable,
1579f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               ITestNGMethod testMethod,
1580f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               ITestResult testResult,
1581f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               int failureCount) {
1582dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    if (throwable != null) {
1583dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin      testResult.setThrowable(throwable);
1584dbe729282b45780f21cfede19ef4ab0b206423efVladislav Rassokhin    }
1585f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int successPercentage= testMethod.getSuccessPercentage();
1586f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int invocationCount= testMethod.getInvocationCount();
158721dad3370294d6595fdddc3faf55792f60a913f1nullin    float numberOfTestsThatCanFail= ((100 - successPercentage) * invocationCount) / 100f;
1588f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1589f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(failureCount < numberOfTestsThatCanFail) {
1590f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.SUCCESS_PERCENTAGE_FAILURE);
1591f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1592f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else {
1593f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.FAILURE);
1594f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1595f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1596f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1597f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
15989d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  static interface Predicate<K, T> {
15999d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    boolean isTrue(K k, T v);
16009d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  }
1601f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16029d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  static class CanRunFromClassPredicate implements Predicate <ITestNGMethod, IClass> {
16039d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    @Override
16049d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    public boolean isTrue(ITestNGMethod m, IClass v) {
16059d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      return m.canRunFromClass(v);
1606f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1607f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1608f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16099d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  static class SameClassNamePredicate implements Predicate<ITestNGMethod, IClass> {
16109d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    @Override
16119d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    public boolean isTrue(ITestNGMethod m, IClass c) {
16129d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      return c == null || m.getTestClass().getName().equals(c.getName());
1613f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
16149d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  }
1615f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16169d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  /**
16179d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust   * @return Only the ITestNGMethods applicable for this testClass
16189d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust   */
16199d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust  private ITestNGMethod[] filterMethods(IClass testClass, ITestNGMethod[] methods,
16209d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      Predicate<ITestNGMethod, IClass> predicate) {
1621ed0917f31f0b66158bc786cd018fd95175f76f29Cédric Beust    List<ITestNGMethod> vResult= Lists.newArrayList();
1622f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1623f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(ITestNGMethod tm : methods) {
16249d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      if (predicate.isTrue(tm, testClass)) {
16259d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust        log(10, "Keeping method " + tm + " for class " + testClass);
1626f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        vResult.add(tm);
16279d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust      } else {
16289d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust        log(10, "Filtering out method " + tm + " for class " + testClass);
1629f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1630f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1631f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
16329d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    ITestNGMethod[] result= vResult.toArray(new ITestNGMethod[vResult.size()]);
16339d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust
16349d4f222d9afb9d19ad55dc77b39d9a36a28e7ea3Cédric Beust    return result;
1635f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1636f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1637f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
16386671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin   * @return true if this method depends on certain methods.
1639f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1640f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean dependsOnMethods(ITestNGMethod tm) {
1641e934f66fb4fb247ebf5fec45770bc6820fbba29anullin    String[] methods = tm.getMethodsDependedUpon();
16426671e96405df2adae17d234e3ea0bd0d2c5f7555Vladislav Rassokhin    return null != methods && methods.length > 0;
1643f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1644f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1645ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust  private void runConfigurationListeners(ITestResult tr, boolean before) {
1646ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    if (before) {
1647ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust      for(IConfigurationListener icl: m_notifier.getConfigurationListeners()) {
1648eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beust        if (icl instanceof IConfigurationListener2) {
1649eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beust          ((IConfigurationListener2) icl).beforeConfiguration(tr);
1650eef09e0a0ec23bcea1995c0813ca6d29580c7869Cédric Beust        }
1651ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust      }
1652ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust    } else {
1653ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust      for(IConfigurationListener icl: m_notifier.getConfigurationListeners()) {
1654ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust        switch(tr.getStatus()) {
1655ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust          case ITestResult.SKIP:
1656ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            icl.onConfigurationSkip(tr);
1657ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            break;
1658ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust          case ITestResult.FAILURE:
1659ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            icl.onConfigurationFailure(tr);
1660ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            break;
1661ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust          case ITestResult.SUCCESS:
1662ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            icl.onConfigurationSuccess(tr);
1663ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust            break;
1664ee8e37d41d7e14252ee649f13768022fee714afbCédric Beust        }
1665f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1666f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1667f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
166889fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1669c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust  void runTestListeners(ITestResult tr) {
1670f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    runTestListeners(tr, m_notifier.getTestListeners());
1671f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
167289fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1673f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  // TODO: move this from here as it is directly called from TestNG
1674f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public static void runTestListeners(ITestResult tr, List<ITestListener> listeners) {
1675f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (ITestListener itl : listeners) {
1676f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      switch(tr.getStatus()) {
1677f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SKIP: {
1678f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestSkipped(tr);
1679f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1680f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1681f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SUCCESS_PERCENTAGE_FAILURE: {
1682f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestFailedButWithinSuccessPercentage(tr);
1683f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1684f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1685f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.FAILURE: {
1686f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestFailure(tr);
1687f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1688f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1689f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SUCCESS: {
1690f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestSuccess(tr);
1691f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1692f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1693f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1694f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.STARTED: {
1695f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestStart(tr);
1696f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1697f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1698f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1699f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        default: {
1700f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          assert false : "UNKNOWN STATUS:" + tr;
1701f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1702f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1703f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1704f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1705f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1706f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void log(int level, String s) {
1707f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Utils.log("Invoker " + Thread.currentThread().hashCode(), level, s);
1708f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
170989fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1710eddb4a9423c14fee808a30e92ad77a16e88b320enullin  /**
1711c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin   * This class holds a {@code ParameterHolder} or in case of an error, a non-null
1712eddb4a9423c14fee808a30e92ad77a16e88b320enullin   * {@code TestResult} containing the cause
1713eddb4a9423c14fee808a30e92ad77a16e88b320enullin   */
1714f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private static class ParameterBag {
1715c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust    final ParameterHolder parameterHolder;
1716c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    final ITestResult errorResult;
171789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1718c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    public ParameterBag(ParameterHolder parameterHolder) {
1719c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.parameterHolder = parameterHolder;
1720c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.errorResult = null;
1721c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    }
1722c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin
1723c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin    public ParameterBag(ITestResult errorResult) {
1724c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.parameterHolder = null;
1725c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      this.errorResult = errorResult;
1726f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
172789fa9de5273ba0e09ed99e5e116ecd9910c9c374nullin
1728f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public boolean hasErrors() {
1729c2a2dc91fe71191ce77dd86112daeefed4e1aaa6Vladislav Rassokhin      return errorResult != null;
1730f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1731f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1732c90ac0f51ccdf22d9430a8264ddd2d4966b36f81Cédric Beust
1733f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust}
1734