Invoker.java revision d7e500014dc797345bc2e4f9ceb176fa225b8a37
1f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustpackage org.testng.internal;
2f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
3f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
4f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.lang.reflect.InvocationTargetException;
5f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.lang.reflect.Method;
6f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.util.ArrayList;
7f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.util.HashMap;
8f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.util.Hashtable;
9f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.util.Iterator;
10f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.util.List;
11f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.util.Map;
12f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport java.util.Set;
13f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
14f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IClass;
15f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IHookable;
16f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.IRetryAnalyzer;
17f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestClass;
18f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestContext;
19f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestListener;
20f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestNGMethod;
21f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.ITestResult;
22f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.Reporter;
23f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.SkipException;
24f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.SuiteRunState;
25f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.TestException;
26f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.TestNGException;
27f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.InvokeMethodRunnable.TestNGRuntimeException;
28f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.annotations.AnnotationHelper;
29f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.annotations.IAnnotationFinder;
30f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.annotations.IConfiguration;
31f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.thread.ThreadExecutionException;
32f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.internal.thread.ThreadUtil;
33f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlClass;
34f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlSuite;
35f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustimport org.testng.xml.XmlTest;
36f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
37f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust/**
38f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * This class is responsible for invoking methods:
39f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - test methods
40f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - configuration methods
41f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * - possibly in a separate thread
42f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * and then for notifying the result listeners.
43f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust *
44f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
45f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
46f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust */
47f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beustpublic class Invoker implements IInvoker {
48f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ITestContext m_testContext;
49f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ITestResultNotifier m_notifier;
50f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private IAnnotationFinder m_annotationFinder;
51f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private SuiteRunState m_suiteState;
526cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust  private boolean m_skipFailedInvocationCounts;
53f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
54f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public Invoker(ITestContext testContext,
55f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                 ITestResultNotifier notifier,
56f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                 SuiteRunState state,
576cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                 IAnnotationFinder annotationFinder,
586cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                 boolean skipFailedInvocationCounts) {
59f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_testContext= testContext;
60f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_suiteState= state;
61f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_notifier= notifier;
62f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_annotationFinder= annotationFinder;
636cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust    m_skipFailedInvocationCounts = skipFailedInvocationCounts;
64f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
65f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
66f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
67f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Invoke configuration methods if they belong to the same TestClass passed
68f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * in parameter.. <p/>TODO: Calculate ahead of time which methods should be
69f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * invoked for each class. Might speed things up for users who invoke the
70f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * same test class with different parameters in the same suite run.
71f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   *
72f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * If instance is non-null, the configuration will be run on it.  If it is null,
73f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * the configuration methods will be run on all the instances retrieved
74f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * from the ITestClass.
75f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
76f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public void invokeConfigurations(IClass testClass,
77f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] allMethods,
78f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
79f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
80f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Object instance)
81f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
82f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    invokeConfigurations(testClass, null, allMethods, suite, params, instance);
83f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
84f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
85f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void invokeConfigurations(IClass testClass,
86f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod currentTestMethod,
87f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] allMethods,
88f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
89f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
90f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Object instance)
91f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
92f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == allMethods) {
93f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      log(5, "No @Configuration methods found");
94f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
95f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return;
96f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
97f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
98f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ITestNGMethod[] methods= filterMethodsUnique(testClass, allMethods);
99f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
100f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(ITestNGMethod tm : methods) {
101f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(null == testClass) {
102f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testClass= tm.getTestClass();
103f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
104f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
105f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestResult testResult= new TestResult(testClass,
106f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             instance,
107f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             tm,
108f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             null,
109f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             System.currentTimeMillis(),
110f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             System.currentTimeMillis());
111f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
112f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      IConfiguration configurationAnnotation= null;
113f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      try {
114f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Object[] instances= tm.getInstances();
115f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (instances == null || instances.length == 0) instances = new Object[] { instance };
116f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Class<?> objectClass= instances[0].getClass();
117f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Method method= tm.getMethod();
118f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
119f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Only run the configuration if
120f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // - the test is enabled and
121f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // - the Configuration method belongs to the same class or a parent
122f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(MethodHelper.isEnabled(objectClass, m_annotationFinder)) {
123f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          configurationAnnotation= (IConfiguration) AnnotationHelper.findConfiguration(m_annotationFinder, method);
124f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
125f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          boolean isClassConfiguration= isClassConfiguration(configurationAnnotation);
126f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          boolean alwaysRun= isAlwaysRun(configurationAnnotation);
127f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
128f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          if(!confInvocationPassed(tm) && !alwaysRun) {
129f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            handleConfigurationSkip(tm, testResult);
130f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            continue;
131f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
132f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
133f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          log(3, "Invoking " + Utils.detailedMethodName(tm, true));
134f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
135f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          Object[] parameters= Parameters.createConfigurationParameters(tm.getMethod(),
136f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                                        params,
137f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                                        currentTestMethod,
138f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                                        m_annotationFinder,
139f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                                        suite,
140f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                                        m_testContext);
141f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testResult.setParameters(parameters);
142f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
143f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          Object[] newInstances= (null != instance) ? new Object[] { instance } : instances;
144f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
145ec9d2748fd87c650757fe06ee7cff536ee0bbc40Cédric Beust          invokeConfigurationMethod(newInstances, tm,
146ec9d2748fd87c650757fe06ee7cff536ee0bbc40Cédric Beust            parameters, isClassConfiguration, testResult);
147f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
148f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // TODO: probably we should trigger the event for each instance???
149f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testResult.setEndMillis(System.currentTimeMillis());
150f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          runConfigurationListeners(testResult);
151f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        } // if is enabled
152f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else {
153f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          log(3,
154f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              "Skipping "
155f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + Utils.detailedMethodName(tm, true)
156f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + " because "
157f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + objectClass.getName()
158f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + " is not enabled");
159f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
160f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
161f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      catch(InvocationTargetException ex) {
162f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, suite);
163f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
164f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      catch(TestNGException ex) {
165f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Don't wrap TestNGExceptions, it could be a missing parameter on a
166f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // @Configuration method
167f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, suite);
168f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
169f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      catch(Throwable ex) { // covers the non-wrapper exceptions
170f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, suite);
171f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
172f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // for methods
173f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
174f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
175f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
176f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Marks the currect <code>TestResult</code> as skipped and invokes the listeners.
177f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
178f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void handleConfigurationSkip(ITestNGMethod tm, ITestResult testResult) {
179f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    testResult.setStatus(ITestResult.SKIP);
180f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    runConfigurationListeners(testResult);
181f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
182f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
183f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
184f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Is the current <code>IConfiguration</code> a class-level method.
185f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
186f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private  boolean isClassConfiguration(IConfiguration configurationAnnotation) {
187f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == configurationAnnotation) {
188f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return false;
189f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
190f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
191f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean before= (null != configurationAnnotation)
192f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ? configurationAnnotation.getBeforeTestClass()
193f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      : false;
194f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
195f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean after= (null != configurationAnnotation)
196f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ? configurationAnnotation.getAfterTestClass()
197f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      : false;
198f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
199f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return (before || after);
200f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
201f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
202f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
203f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Is the <code>IConfiguration</code> marked as alwaysRun.
204f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
205f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean isAlwaysRun(IConfiguration configurationAnnotation) {
206f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == configurationAnnotation) {
207f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return false;
208f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
209f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
210f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean alwaysRun= false;
211f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if ((configurationAnnotation.getAfterSuite()
212f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        || configurationAnnotation.getAfterTest()
213f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        || configurationAnnotation.getAfterTestClass()
214f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        || configurationAnnotation.getAfterTestMethod())
215f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        && configurationAnnotation.getAlwaysRun())
216f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    {
217f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        alwaysRun= true;
218f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
219f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
220f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return alwaysRun;
221f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
222f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
223f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void handleConfigurationFailure(Throwable ite,
224f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          ITestNGMethod tm,
225f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          ITestResult testResult,
226f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          IConfiguration annotation,
227f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          XmlSuite suite)
228f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
229f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Throwable cause= ite.getCause() != null ? ite.getCause() : ite;
230f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
231f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(SkipException.class.isAssignableFrom(cause.getClass())) {
232f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      SkipException skipEx= (SkipException) cause;
233f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(!skipEx.isSkip()) {
234f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setThrowable(skipEx);
235f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        handleConfigurationSkip(tm, testResult);
236f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        return;
237f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
238f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
239f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Utils.log("", 3, "Failed to invoke @Configuration method "
240f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        + tm.getRealClass().getName() + "." + tm.getMethodName() + ":" + cause.getMessage());
241f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    handleException(cause, tm, testResult, 1);
242f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    runConfigurationListeners(testResult);
243f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
244f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
245f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If in TestNG mode, need to take a look at the annotation to figure out
246f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // what kind of @Configuration method we're dealing with
247f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
248f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (null != annotation) {
249f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      recordConfigurationInvocationFailed(tm, annotation, suite);
250f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
251f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
252f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
253f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
254f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return All the classes that belong to the same <test> tag as @param cls
255f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
256f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private XmlClass[] findClassesInSameTest(Class<?> cls, XmlSuite suite) {
257f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Map<String, XmlClass> vResult= new HashMap<String, XmlClass>();
258f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String className= cls.getName();
259f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(XmlTest test : suite.getTests()) {
260f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(XmlClass testClass : test.getXmlClasses()) {
261f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(testClass.getName().equals(className)) {
262f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
263f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // Found it, add all the classes in this test in the result
264f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          for(XmlClass thisClass : test.getXmlClasses()) {
265f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            vResult.put(thisClass.getName(), thisClass);
266f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
267f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // Note:  we need to iterate through the entire suite since the same
268f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // class might appear in several <test> tags
269f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
270f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
271f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
272f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
273f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    XmlClass[] result= vResult.values().toArray(new XmlClass[vResult.size()]);
274f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
275f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
276f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
277f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
278f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
279f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Record internally the failure of a Configuration, so that we can determine
280f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * later if @Test should be skipped.
281f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
282f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void recordConfigurationInvocationFailed(ITestNGMethod tm, IConfiguration annotation, XmlSuite suite) {
283f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If beforeTestClass/beforeTestMethod or afterTestClass/afterTestMethod
284f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // failed, mark this entire class as failed, but only this class (the other
285f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // classes should keep running normally)
286f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(annotation.getBeforeTestClass()
287f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      || annotation.getAfterTestClass()
288f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      || annotation.getBeforeTestMethod()
289f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      || annotation.getAfterTestMethod())
290f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    {
291f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      setClassInvocationFailure(tm.getRealClass(), false);
292f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
293f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
294f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If beforeSuite or afterSuite failed, mark *all* the classes as failed
295f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // for configurations.  At this point, the entire Suite is screwed
296f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else if (annotation.getBeforeSuite() || annotation.getAfterSuite()) {
297f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_suiteState.failed();
298f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
299f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
300f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // beforeTest or afterTest:  mark all the classes in the same
301f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // <test> stanza as failed for configuration
302f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else if (annotation.getBeforeTest() || annotation.getAfterTest()) {
303f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlClass[] classes= findClassesInSameTest(tm.getRealClass(), suite);
304f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(XmlClass xmlClass : classes) {
305f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        setClassInvocationFailure(xmlClass.getSupportClass(), false);
306f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
307f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
308f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] beforeGroups= annotation.getBeforeGroups();
309f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null != beforeGroups && beforeGroups.length > 0) {
310f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(String group: beforeGroups) {
311f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        m_beforegroupsFailures.put(group, Boolean.FALSE);
312f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
313f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
314f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
315f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
316f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
317f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if this class has successfully run all its @Configuration
318f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * method or false if at least one of these methods failed.
319f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
320f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean confInvocationPassed(ITestNGMethod method) {
321f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean result= true;
322f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
323f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Class<?> cls= method.getMethod().getDeclaringClass();
324f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
325f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(m_suiteState.isFailed()) {
326f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      result= false;
327f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
328f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else {
329f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(m_classInvocationResults.containsKey(cls)) {
330f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        result= m_classInvocationResults.get(cls);
331f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
332f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
333f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        for(Class<?> clazz: m_classInvocationResults.keySet()) {
334f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          if(clazz.isAssignableFrom(cls)) {
335f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            result= false;
336f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            break;
337f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
338f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
339f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
340f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
341f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
342f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // check if there are failed @BeforeGroups
343f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] groups= method.getGroups();
344f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null != groups && groups.length > 0) {
345f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(String group: groups) {
346f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(m_beforegroupsFailures.containsKey(group)) {
347f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          result= false;
348f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
349f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
350f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
351f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
352f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
353f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
354f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
355f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /** Group failures must be synched as the Invoker is accessed concurrently */
356f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private Map<String, Boolean> m_beforegroupsFailures= new Hashtable<String, Boolean>();
357f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
358f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /** Class failures must be synched as the Invoker is accessed concurrently */
359f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private Map<Class<?>, Boolean> m_classInvocationResults= new Hashtable<Class<?>, Boolean>();
360f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
361f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void setClassInvocationFailure(Class<?> clazz, boolean flag) {
362f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    m_classInvocationResults.put(clazz, flag);
363f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
364f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
365f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
366f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Effectively invokes a configuration method on all passed in instances.
367f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   *
368f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param instances the instances to invoke the configuration method on
369f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param tm the configuration method
370f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param params the parameters needed for method invocation
371f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param isClass flag if the configuration method is a class level method // FIXME: this looks like a missusage
372f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param testResult
373f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @throws InvocationTargetException
374f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @throws IllegalAccessException
375f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
376f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void invokeConfigurationMethod(Object[] instances,
377f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         ITestNGMethod tm,
378f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         Object[] params,
379f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         boolean isClass,
380f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                         ITestResult testResult)
381f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    throws InvocationTargetException, IllegalAccessException
382f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
383f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Mark this method with the current thread id
384f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    tm.setId(ThreadUtil.currentThreadInfo());
385f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
386f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(Object targetInstance : instances) {
387f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      InvokedMethod im= new InvokedMethod(targetInstance,
388f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          tm,
389f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          params,
390f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          false, /* isTest */
391f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          isClass, /* ??? */
392f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                          System.currentTimeMillis());
393f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
394f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_notifier.addInvokedMethod(im);
395f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
396f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      try {
397f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Reporter.setCurrentTestResult(testResult);
398f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        MethodHelper.invokeMethod(tm.getMethod(), targetInstance, params);
399f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
400f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      finally {
401f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Reporter.setCurrentTestResult(testResult);
402f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
403f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
404f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
405f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
406f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ITestResult invokeMethod(Object[] instances,
407f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   int instanceIndex,
408f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   final ITestNGMethod tm,
409f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Object[] parameterValues,
410f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   XmlSuite suite,
411f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   Map<String, String> params,
412f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestClass testClass,
413f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] beforeMethods,
414f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ITestNGMethod[] afterMethods,
415f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                   ConfigurationGroupMethods groupMethods) {
416f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
417f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Invoke beforeGroups configurations
418f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
419f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    invokeBeforeGroupsConfigurations(testClass, tm, groupMethods, suite, params,
420f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        instances[instanceIndex]);
421f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
422f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
42345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // Invoke beforeMethods only if
42445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // - firstTimeOnly is not set
42545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    // - firstTimeOnly is set, and we are reaching at the first invocationCount
426f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
42745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    invokeConfigurations(testClass, tm,
42845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      filterConfigurationMethods(tm, beforeMethods, true /* beforeMethods */),
42945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      suite, params,
43045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      instances[instanceIndex]);
431f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
432f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
433f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Create the ExtraOutput for this method
434f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
435f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    TestResult testResult = null;
436f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    try {
437f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult= new TestResult(testClass, instances[instanceIndex],
438f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 tm,
439f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 null,
440f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 System.currentTimeMillis(),
441f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                 0);
442f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setParameters(parameterValues);
443f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setHost(m_testContext.getHost());
444f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.STARTED);
445f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      runTestListeners(testResult);
446f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
447f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      InvokedMethod invokedMethod= new InvokedMethod(instances[instanceIndex],
448f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          tm,
449f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          parameterValues,
450f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          true,
451f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          false,
452f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          System.currentTimeMillis());
453f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
454f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_notifier.addInvokedMethod(invokedMethod);
455f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
456f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Method thisMethod= tm.getMethod();
457f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
458f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(confInvocationPassed(tm)) {
459f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        log(3, "Invoking " + thisMethod.getDeclaringClass().getName() + "." +
460f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            thisMethod.getName());
461f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
462f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // If no timeOut, just invoke the method
463f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(tm.getTimeOut() <= 0) {
464f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          //
465f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // If this method is a IHookable, invoke its run() method
466f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          //
467f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          if (IHookable.class.isAssignableFrom(thisMethod.getDeclaringClass())) {
468f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            MethodHelper.invokeHookable(instances[instanceIndex],
469f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                parameterValues, testClass, thisMethod, testResult);
470f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            testResult.setStatus(ITestResult.SUCCESS);
471f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
472f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          //
473f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          // Not a IHookable, invoke directly
474f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          //
475f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          else {
476f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            try {
477f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              Reporter.setCurrentTestResult(testResult);
478f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              MethodHelper.invokeMethod(thisMethod, instances[instanceIndex],
479f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  parameterValues);
480f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              testResult.setStatus(ITestResult.SUCCESS);
481f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            }
482f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            finally {
483f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              Reporter.setCurrentTestResult(null);
484f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            }
485f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
486f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
487f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else {
488f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          try {
489f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            Reporter.setCurrentTestResult(testResult);
490f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            MethodHelper.invokeWithTimeout(tm, instances[instanceIndex],
491f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                parameterValues, testResult);
492f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
493f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          finally {
494f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            Reporter.setCurrentTestResult(null);
495f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
496f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
497f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
498f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
499f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setStatus(ITestResult.SKIP);
500f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
501f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
502f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(InvocationTargetException ite) {
503f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setThrowable(ite.getCause());
504f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
505f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(ThreadExecutionException tee) { // wrapper for TestNGRuntimeException
506f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Throwable cause= tee.getCause();
507f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(TestNGRuntimeException.class.equals(cause.getClass())) {
508f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setThrowable(cause.getCause());
509f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
510f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
511f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setThrowable(cause);
512f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
513f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
514f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(Throwable thr) { // covers the non-wrapper exceptions
515f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setThrowable(thr);
516f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
517f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    finally {
518f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
519f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Increment the invocation count for this method
520f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
521f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      tm.incrementCurrentInvocationCount();
522f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
523f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (testResult != null) {
524f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setEndMillis(System.currentTimeMillis());
525f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
526f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
52745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // Invoke afterMethods only if
52845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // - lastTimeOnly is not set
52945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // - lastTimeOnly is set, and we are reaching the last invocationCount
530f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
53145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      invokeConfigurations(testClass, tm,
53245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          filterConfigurationMethods(tm, afterMethods, false /* beforeMethods */),
53345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          suite, params,
534f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          instances[instanceIndex]);
535f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
536f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
53745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      // Invoke afterGroups configurations
538f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
539f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeAfterGroupsConfigurations(testClass, tm, groupMethods, suite,
540f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          params, instances[instanceIndex]);
541f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
542f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return testResult;
543f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
544f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
545f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
54645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * The array of methods contains @BeforeMethods if isBefore if true, @AfterMethods
54745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * otherwise.  This function removes all the methods that should not be run at this
54845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * point because they are either firstTimeOnly or lastTimeOnly and we haven't reached
54945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   * the current invocationCount yet
55045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust   */
55145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  private ITestNGMethod[] filterConfigurationMethods(ITestNGMethod tm,
55245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      ITestNGMethod[] methods, boolean isBefore)
55345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  {
55445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    List<ITestNGMethod> result = new ArrayList<ITestNGMethod>();
55545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    for (ITestNGMethod m : methods) {
55645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      ConfigurationMethod cm = (ConfigurationMethod) m;
55745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      if (isBefore) {
55845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        if (! cm.isFirstTimeOnly() ||
55945a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust            (cm.isFirstTimeOnly() && tm.getCurrentInvocationCount() == 0))
56045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        {
56145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          result.add(m);
56245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        }
56345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      }
56445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      else {
565d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        int current = tm.getCurrentInvocationCount();
566d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        boolean isLast = false;
567d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        if (tm.getParameterInvocationCount() > 0) {
568d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust          isLast = current == tm.getParameterInvocationCount();
569d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        }
570d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        else if (tm.getInvocationCount() > 1) {
571d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust          isLast = current == tm.getInvocationCount();
572d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        }
573d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust//        boolean isLastInvocationCount
574d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust//          = tm.getInvocationCount() == 1 ||
575d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust//            current == tm.getInvocationCount();
576d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust//        boolean isLastParameterInvocationCount
577d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust//          = tm.getParameterInvocationCount() > 0 &&
578d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust//            current == tm.getParameterInvocationCount();
579d7e500014dc797345bc2e4f9ceb176fa225b8a37Cédric Beust        if (! cm.isLastTimeOnly() || (cm.isLastTimeOnly() && isLast)) {
58045a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust          result.add(m);
58145a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust        }
58245a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust      }
58345a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    }
58445a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust
58545a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust    return result.toArray(new ITestNGMethod[result.size()]);
58645a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  }
58745a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust
58845a161fb7f6ba0937ec480fef1a803524bc07214Cédric Beust  /**
589f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * {@link #invokeTestMethods()} eventually converge here to invoke a single @Test method.
590f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
591f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * This method is responsible for actually invoking the method. It decides if the invocation
592f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * must be done:
593f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <ul>
594f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <li>through an <code>IHookable</code></li>
595f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <li>directly (through reflection)</li>
596f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <li>in a separate thread (in case it needs to timeout)
597f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * </ul>
598f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   *
599f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
600f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * This method is also reponsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup
601f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * if it is the case for the passed in @Test method.
602f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
603f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private List<ITestResult> invokeTestMethod(Object[] instances,
604f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             final ITestNGMethod tm,
605f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Object[] parameterValues,
606f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             XmlSuite suite,
607f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Map<String, String> params,
608f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestClass testClass,
609f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestNGMethod[] beforeMethods,
610f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestNGMethod[] afterMethods,
611f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ConfigurationGroupMethods groupMethods)
612f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
613f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<ITestResult> results = new ArrayList<ITestResult>();
614f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
615f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Mark this method with the current thread id
616f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    tm.setId(ThreadUtil.currentThreadInfo());
617f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
618f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(int i= 0; i < instances.length; i++) {
619f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      results.add(
620f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          invokeMethod(instances, i, tm, parameterValues, suite, params,
621f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              testClass, beforeMethods, afterMethods, groupMethods));
622f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
623f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
624f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return results;
625f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
626f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
627f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
628f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Filter all the beforeGroups methods and invoke only those that apply
629f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * to the current test method
630f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
631f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void invokeBeforeGroupsConfigurations(ITestClass testClass,
632f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                ITestNGMethod currentTestMethod,
633f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                ConfigurationGroupMethods groupMethods,
634f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                XmlSuite suite,
635f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                Map<String, String> params,
636f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                Object instance)
637f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
638f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    synchronized(groupMethods) {
639f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      List<ITestNGMethod> filteredMethods = new ArrayList<ITestNGMethod>();
640f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      String[] groups = currentTestMethod.getGroups();
641f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, List<ITestNGMethod>> beforeGroupMap = groupMethods.getBeforeGroupsMap();
642f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
643f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String group : groups) {
644f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        List<ITestNGMethod> methods = beforeGroupMap.get(group);
645f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (methods != null) {
646f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          filteredMethods.addAll(methods);
647f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
648f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
649f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
650f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] beforeMethodsArray = filteredMethods.toArray(new ITestNGMethod[filteredMethods.size()]);
651f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
652f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Invoke the right groups methods
653f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
654f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(beforeMethodsArray.length > 0) {
655f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // don't pass the IClass or the instance as the method may be external
656f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // the invocation must be similar to @BeforeTest/@BeforeSuite
657f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        invokeConfigurations(null, beforeMethodsArray, suite, params, null);
658f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
659f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
660f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
661f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Remove them so they don't get run again
662f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      //
663f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      groupMethods.removeBeforeGroups(groups);
664f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
665f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
666f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
667f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void invokeAfterGroupsConfigurations(ITestClass testClass,
668f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               ITestNGMethod currentTestMethod,
669f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               ConfigurationGroupMethods groupMethods,
670f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               XmlSuite suite,
671f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               Map<String, String> params,
672f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               Object instance)
673f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
674f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Skip this if the current method doesn't belong to any group
675f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // (only a method that belongs to a group can trigger the invocation
676f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // of afterGroups methods)
677f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (currentTestMethod.getGroups().length == 0) return;
678f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
679f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // See if the currentMethod is the last method in any of the groups
680f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // it belongs to
681f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Map<String, String> filteredGroups = new HashMap<String, String>();
682f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] groups = currentTestMethod.getGroups();
683f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    synchronized(groupMethods) {
684f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String group : groups) {
685f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (groupMethods.isLastMethodForGroup(group, currentTestMethod)) {
686f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          filteredGroups.put(group, group);
687f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
688f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
689f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
690f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(filteredGroups.isEmpty()) return;
691f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
692f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // The list of afterMethods to run
693f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<ITestNGMethod, ITestNGMethod> afterMethods = new HashMap<ITestNGMethod, ITestNGMethod>();
694f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
695f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Now filteredGroups contains all the groups for which we need to run the afterGroups
696f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // method.  Find all the methods that correspond to these groups and invoke them.
697f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, List<ITestNGMethod>> map = groupMethods.getAfterGroupsMap();
698f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (String g : filteredGroups.values()) {
699f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        List<ITestNGMethod> methods = map.get(g);
700f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Note:  should put them in a map if we want to make sure the same afterGroups
701f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // doesn't get run twice
702f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (methods != null) {
703f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          for (ITestNGMethod m : methods) {
704f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            afterMethods.put(m, m);
705f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
706f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
707f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
708f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
709f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Got our afterMethods, invoke them
710f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] afterMethodsArray = afterMethods.keySet().toArray(new ITestNGMethod[afterMethods.size()]);
711f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // don't pass the IClass or the instance as the method may be external
712f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // the invocation must be similar to @BeforeTest/@BeforeSuite
713f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeConfigurations(null, afterMethodsArray, suite, params, null);
714f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
715f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Remove the groups so they don't get run again
716f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      groupMethods.removeAfterGroups(filteredGroups.keySet());
717f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
718f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
719f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
720f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private Object[] getParametersFromIndex(Iterator<Object[]> parametersValues, int index) {
721f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while (parametersValues.hasNext()) {
722f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object[] parameters = parametersValues.next();
723f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
724f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (index == 0) {
725f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        return parameters;
726f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
727f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      index--;
728f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
729f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return null;
730f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
731f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
732f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private int retryFailed(Object[] instances,
733f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           int instanceIndex,
734f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           final ITestNGMethod tm,
735f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           XmlSuite suite,
736f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestClass testClass,
737f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestNGMethod[] beforeMethods,
738f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestNGMethod[] afterMethods,
739f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ConfigurationGroupMethods groupMethods,
740f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           List<ITestResult> result,
741f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           int failureCount,
742f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           Class<?>[] expectedExceptionClasses,
743f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           ITestContext testContext,
744f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           Map<String, String> parameters,
745f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                           int parametersIndex) {
74692206009b23ecbbf29e5a0d20f6b095a552afcb8Cédric Beust    List<Object> failedInstances;
747f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
74892206009b23ecbbf29e5a0d20f6b095a552afcb8Cédric Beust    do {
74992206009b23ecbbf29e5a0d20f6b095a552afcb8Cédric Beust      failedInstances = new ArrayList<Object>();
750f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> allParameters = new HashMap<String, String>();
751f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      /**
752f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       * TODO: This recreates all the parameters every time when we only need
753f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       * one specific set. Should optimize it by only recreating the set needed.
754f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust       */
755f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ParameterBag bag = createParameters(testClass, tm, parameters,
756f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          allParameters, suite, testContext);
757f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object[] parameterValues = getParametersFromIndex(bag.parameterValues, parametersIndex);
758f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
759f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      result.add(
760f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          invokeMethod(instances, instanceIndex, tm, parameterValues, suite,
761f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              allParameters, testClass, beforeMethods, afterMethods, groupMethods));
762f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      failureCount = handleInvocationResults(tm, result, failedInstances,
763f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          failureCount, expectedExceptionClasses, true);
764f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
765f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while (!failedInstances.isEmpty());
766f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return failureCount;
767f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
768f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
769f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ParameterBag createParameters(ITestClass testClass,
770f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        ITestNGMethod testMethod,
771f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        Map<String, String> parameters,
772f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        Map<String, String> allParameterNames,
773f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        XmlSuite suite,
774f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                        ITestContext testContext) {
775f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Object instance = testClass.getInstances(true)[0];
776f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ParameterBag bag= handleParameters(testMethod,
777f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        instance, allParameterNames, parameters, suite, testContext);
778f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
779f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return bag;
780f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
781f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
782f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
783f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Invoke all the test methods.  Note the plural:  the method passed in
784f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * parameter might be invoked several times if the test class it belongs
785f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * to has more than one instance (i.e., if an @Factory method has been
786f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * declared somewhere that returns several instances of this TestClass).
787f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * If no @Factory method was specified, testMethod will only be invoked
788f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * once.
789f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * <p/>
790f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Note that this method also takes care of invoking the beforeTestMethod
791f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * and afterTestMethod, if any.
792f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   *
793f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Note (alex): this method can be refactored to use a SingleTestMethodWorker that
794f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * directly invokes
795f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * {@link #invokeTestMethod(Object[], ITestNGMethod, Object[], XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods)}
796f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * and this would simplify the implementation (see how DataTestMethodWorker is used)
797f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
798f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public List<ITestResult> invokeTestMethods(ITestNGMethod testMethod,
799f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestNGMethod[] allTestMethods,
800f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             int testMethodIndex,
801f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             XmlSuite suite,
802f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Map<String, String> parameters,
803f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ConfigurationGroupMethods groupMethods,
804f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             Object[] instances,
805f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                             ITestContext testContext)
806f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
807f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Potential bug here if the test method was declared on a parent class
808f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    assert null != testMethod.getTestClass()
809f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    : "COULDN'T FIND TESTCLASS FOR " + testMethod.getMethod().getDeclaringClass();
810f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
811f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<ITestResult> result = new ArrayList<ITestResult>();
812f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
813f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ITestClass testClass= testMethod.getTestClass();
814f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    long start= System.currentTimeMillis();
815f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
816f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
817f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // TODO:
818f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // - [DONE] revisit invocationCount, threadPoolSize values
819f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // - try to remove the isWithinThreadedMethod: still needed to determine the @BeforeMethod + @AfterMethod
820f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // - [DONE] solve the results different approaches: assignment and addAll
821f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
8226cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust    // For invocationCount>1 and threadPoolSize>1 the method will be invoked on a thread pool
823f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int invocationCount = (testMethod.getThreadPoolSize() > 1 ? 1 : testMethod.getInvocationCount());
824f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
825f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int failureCount = 0;
826f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
827f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Class<?>[] expectedExceptionClasses =
828f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        MethodHelper.findExpectedExceptions(m_annotationFinder, testMethod.getMethod());
829f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while(invocationCount-- > 0) {
830f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      boolean okToProceed = checkDependencies(testMethod, testClass, allTestMethods);
831f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
832f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (okToProceed) {
833f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        //
834f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Invoke the test method if it's enabled
835f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        //
836f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (MethodHelper.isEnabled(testMethod.getMethod(), m_annotationFinder)) {
837f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            //
8386cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust            // If threadPoolSize specified, run this method in its own pool thread.
839f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            //
840f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            if (testMethod.getThreadPoolSize() > 1 && testMethod.getInvocationCount() > 1) {
841f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                return invokePooledTestMethods(testMethod, allTestMethods, suite,
842f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    parameters, groupMethods, testContext);
843f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            }
844f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
845f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            //
846f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            // No threads, regular invocation
847f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            //
848f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            else {
849f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods());
850f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods());
851f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
852f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
853f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              Map<String, String> allParameterNames = new HashMap<String, String>();
854f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              ParameterBag bag = createParameters(testClass, testMethod,
855f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  parameters, allParameterNames, suite, testContext);
856f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
857f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              if(bag.hasErrors()) {
858f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                failureCount = handleInvocationResults(testMethod,
859f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    bag.errorResults, null, failureCount, expectedExceptionClasses, true);
860f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                // there is nothing we can do more
861f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                continue;
862f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              }
863f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
864f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              Iterator<Object[]> allParameterValues= bag.parameterValues;
865f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
866f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              if(testMethod.getThreadPoolSize() > 1) {
867f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                return invokePooledTestMethods(instances,
868f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      testMethod,
869f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      allTestMethods,
870f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      beforeMethods,
871f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      afterMethods,
872f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      groupMethods,
873f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      suite,
874f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      parameters,
875f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      allParameterNames,
876f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      allParameterValues);
877f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              }
878f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              else {
879f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                int parametersIndex = 0;
880f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
881f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                while (allParameterValues.hasNext()) {
882f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  Object[] parameterValues= allParameterValues.next();
883f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  List<ITestResult> tmpResults = new ArrayList<ITestResult>();
884f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
885f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  try {
886f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    tmpResults.addAll(invokeTestMethod(instances,
887f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       testMethod,
888f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       parameterValues,
889f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       suite,
890f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       allParameterNames,
891f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       testClass,
892f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       beforeMethods,
893f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       afterMethods,
894f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       groupMethods));
895f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  }
896f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  finally {
897f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    List<Object> failedInstances = new ArrayList<Object>();
898f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
899f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    failureCount = handleInvocationResults(testMethod, tmpResults,
900f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                        failedInstances, failureCount, expectedExceptionClasses, true);
901f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    if (failedInstances.isEmpty()) {
902f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      result.addAll(tmpResults);
903f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    } else {
904f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      for (int i = 0; i < failedInstances.size(); i++) {
905f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                        List<ITestResult> retryResults = new ArrayList<ITestResult>();
906f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
9076cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                        failureCount =
9086cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                         retryFailed(failedInstances.toArray(),
9096cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                         i, testMethod, suite, testClass, beforeMethods,
9106cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                         afterMethods, groupMethods, retryResults,
9116cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                         failureCount, expectedExceptionClasses,
9126cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                         testContext, parameters, parametersIndex);
9136cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                      result.addAll(retryResults);
914f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                      }
915f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                    }
9166cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust
9176cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                    //
9186cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                    // If we have a failure, skip all the
9196cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                    // other invocationCounts
9206cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                    //
92161e3a3733701551995e8330db1db52a53a185404Cédric Beust
92261e3a3733701551995e8330db1db52a53a185404Cédric Beust                    // If not specified globally, use the attribute
92361e3a3733701551995e8330db1db52a53a185404Cédric Beust                    // on the annotation
92461e3a3733701551995e8330db1db52a53a185404Cédric Beust                    //
92561e3a3733701551995e8330db1db52a53a185404Cédric Beust                    if (! m_skipFailedInvocationCounts) {
92661e3a3733701551995e8330db1db52a53a185404Cédric Beust                      m_skipFailedInvocationCounts = testMethod.skipFailedInvocations();
92761e3a3733701551995e8330db1db52a53a185404Cédric Beust                    }
9286cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                    if (failureCount > 0 && m_skipFailedInvocationCounts) {
9296cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                      while (invocationCount-- > 0) {
9306cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                        ITestResult r =
9316cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                          new TestResult(testMethod.getTestClass(),
9326cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                            instances[0],
9336cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                            testMethod,
9346cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                            null,
9356cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                            start,
9366cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                            System.currentTimeMillis());
9376cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                        r.setStatus(TestResult.SKIP);
9386cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                        result.add(r);
9396cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                        runTestListeners(r);
9406cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                        m_notifier.addSkippedTest(testMethod, r);
9416cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                      }
9426cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                      break;
9436cf2e96a6b18fe7eecc44cac44bb0690a162f416Cédric Beust                    }
944f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  }
945f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                  parametersIndex++;
946f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                }
947f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              } // for parameters
948f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            }
949f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
950f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        } // isTestMethodEnabled
951f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
952f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      } // okToProceed
953f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
954f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        //
955f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Test is being skipped
956f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        //
957f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        ITestResult testResult= new TestResult(testClass, null,
958f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               testMethod,
959f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               null,
960f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               start,
961f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                               System.currentTimeMillis());
962f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setEndMillis(System.currentTimeMillis());
963f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        String missingGroup = testMethod.getMissingGroup();
964f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (missingGroup != null) {
965f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testResult.setThrowable(new Throwable("Method " + testMethod
966f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              + " depends on nonexistent group \"" + missingGroup + "\""));
967f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
968f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
969f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testResult.setStatus(ITestResult.SKIP);
970f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        m_notifier.addSkippedTest(testMethod, testResult);
971f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        runTestListeners(testResult);
972f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
973f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
974f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
975f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
976f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
977f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  } // invokeTestMethod
978f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
979f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ParameterBag handleParameters(ITestNGMethod testMethod,
980f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object instance,
981f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> allParameterNames,
982f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> parameters,
983f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlSuite suite,
984f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestContext testContext)
985f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
986f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    try {
987f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return new ParameterBag(Parameters.handleParameters(testMethod,
988f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          allParameterNames,
989f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          instance,
990f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          new Parameters.MethodParameters(parameters, testMethod.getMethod(), testContext),
991f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          suite,
992f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_annotationFinder), null);
993f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
994f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    catch(Throwable cause) {
995f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return new ParameterBag(null,
996f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          new TestResult(
997f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              testMethod.getTestClass(),
998f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              instance,
999f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              testMethod,
1000f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              cause,
1001f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              System.currentTimeMillis(),
1002f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              System.currentTimeMillis()));
1003f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1004f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1005f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1006f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1007f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private List<ITestResult> invokePooledTestMethods(Object[] instances,
1008f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod testMethod,
1009f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] allTestMethods,
1010f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] beforeMethods,
1011f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] afterMethods,
1012f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ConfigurationGroupMethods groupMethods,
1013f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlSuite suite,
1014f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> parameters,
1015f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> allParameterNames,
1016f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Iterator<Object[]> allParameterValues)
1017f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1018f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1019f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Create the workers
1020f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1021f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<IMethodWorker> workers= new ArrayList<IMethodWorker>();
1022f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1023f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    while (allParameterValues.hasNext()) {
1024f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Object[] parameterValues= allParameterValues.next();
1025f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      workers.add(new DataTestMethodWorker(instances,
1026f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testMethod.clone(), // we use clones for reporting purposes
1027f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          parameterValues,
1028f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          beforeMethods,
1029f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          afterMethods,
1030f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          groupMethods,
1031f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          suite,
1032f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          allParameterNames));
1033f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1034f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1035f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return runWorkers(testMethod, workers, testMethod.getThreadPoolSize(), groupMethods, suite, parameters);
1036f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1037f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1038f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1039f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * Invokes a method that has a specified threadPoolSize.
1040f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1041f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private List<ITestResult> invokePooledTestMethods(ITestNGMethod testMethod,
1042f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                    ITestNGMethod[] allTestMethods,
1043f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                    XmlSuite suite,
1044f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                    Map<String, String> parameters,
1045f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                    ConfigurationGroupMethods groupMethods,
1046f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                    ITestContext testContext)
1047f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1048f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1049f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Create the workers
1050f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1051f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<IMethodWorker> workers= new ArrayList<IMethodWorker>();
1052f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1053f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (int i = 0; i < testMethod.getInvocationCount(); i++) {
1054f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // we use clones for reporting purposes
1055f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod clonedMethod= testMethod.clone();
1056f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      clonedMethod.setInvocationCount(1);
1057f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      clonedMethod.setThreadPoolSize(1);
1058f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1059f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      MethodInstance mi = new MethodInstance(clonedMethod, clonedMethod.getTestClass().getInstances(true));
1060f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      workers.add(new SingleTestMethodWorker(this,
1061f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          mi,
1062f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          suite,
1063f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          parameters,
1064f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          allTestMethods,
1065f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testContext));
1066f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1067f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1068f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return runWorkers(testMethod, workers, testMethod.getThreadPoolSize(), groupMethods, suite, parameters);
1069f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1070f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1071f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1072f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param testMethod
1073f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param result
1074f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param failureCount
1075f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param expectedExceptionClasses
1076f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return
1077f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1078f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private int handleInvocationResults(ITestNGMethod testMethod,
1079f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                      List<ITestResult> result,
1080f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                      List<Object> failedInstances,
1081f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                      int failureCount,
1082f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                      Class<?>[] expectedExceptionClasses,
1083f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                      boolean triggerListeners) {
1084f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1085f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Go through all the results and create a TestResult for each of them
1086f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1087f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<ITestResult> resultsToRetry = new ArrayList<ITestResult>();
1088f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1089f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (int i = 0; i < result.size(); i++) {
1090f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestResult testResult = result.get(i);
1091f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Throwable ite= testResult.getThrowable();
1092f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      int status= testResult.getStatus();
1093f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1094f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Exception thrown?
1095f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(ite != null) {
1096f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1097f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        //  Invocation caused an exception, see if the method was annotated with @ExpectedException
1098f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(isExpectedException(ite, expectedExceptionClasses)) {
1099f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testResult.setStatus(ITestResult.SUCCESS);
1100f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          status= ITestResult.SUCCESS;
1101f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1102f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else if (SkipException.class.isAssignableFrom(ite.getClass())){
1103f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          SkipException skipEx= (SkipException) ite;
1104f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          if(skipEx.isSkip()) {
1105f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            status= ITestResult.SKIP;
1106f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
1107f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          else {
1108f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            handleException(ite, testMethod, testResult, failureCount++);
1109f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            status= ITestResult.FAILURE;
1110f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
1111f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1112f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else {
1113f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          handleException(ite, testMethod, testResult, failureCount++);
1114f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          status= testResult.getStatus();
1115f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1116f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1117f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1118f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // No exception thrown, make sure we weren't expecting one
1119f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else if(status != ITestResult.SKIP) {
1120f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (expectedExceptionClasses.length > 0) {
1121f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          testResult.setThrowable(
1122f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              new TestException("Expected an exception in test method " + testMethod));
1123f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          status= ITestResult.FAILURE;
1124f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1125f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1126f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1127f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(status);
1128f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1129f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      boolean retry = false;
1130f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1131f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (testResult.getStatus() == ITestResult.FAILURE) {
1132f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        IRetryAnalyzer retryAnalyzer = testMethod.getRetryAnalyzer();
1133f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1134f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (retryAnalyzer != null) {
1135f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          retry = retryAnalyzer.retry(testResult);
1136f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1137f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1138f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (retry) {
1139f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          resultsToRetry.add(testResult);
1140f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          if (failedInstances != null) {
1141f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust            failedInstances.add(testResult.getMethod().getInstances()[i]);
1142f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          }
1143f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1144f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1145f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (!retry) {
1146f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        // Collect the results
1147f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(ITestResult.SUCCESS == status) {
1148f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_notifier.addPassedTest(testMethod, testResult);
1149f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1150f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else if(ITestResult.SKIP == status) {
1151f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_notifier.addSkippedTest(testMethod, testResult);
1152f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1153f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else if(ITestResult.FAILURE == status) {
1154f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_notifier.addFailedTest(testMethod, testResult);
1155f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1156f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) {
1157f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, testResult);
1158f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1159f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        else {
1160f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          assert false : "UNKNOWN STATUS:" + status;
1161f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1162f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1163f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if (triggerListeners) {
1164f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          runTestListeners(testResult);
1165f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1166f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1167f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // for results
1168f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1169f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return removeResultsToRetryFromResult(resultsToRetry, result, failureCount);
1170f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1171f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1172f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private int removeResultsToRetryFromResult(List<ITestResult> resultsToRetry,
1173f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      List<ITestResult> result, int failureCount) {
1174f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (resultsToRetry != null) {
1175f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (ITestResult res : resultsToRetry) {
1176f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        result.remove(res);
1177f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        failureCount--;
1178f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1179f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1180f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return failureCount;
1181f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1182f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1183f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1184f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * To reduce thread contention and also to correctly handle thread-confinement
1185f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * this method invokes the @BeforeGroups and @AfterGroups corresponding to the current @Test method.
1186f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1187f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private List<ITestResult> runWorkers(ITestNGMethod testMethod,
1188f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      List<IMethodWorker> workers,
1189f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      int threadPoolSize,
1190f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ConfigurationGroupMethods groupMethods,
1191f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      XmlSuite suite,
1192f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Map<String, String> parameters)
1193f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1194f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // HINT: invoke @BeforeGroups on the original method (reduce thread contention, and also solve thread confinement)
1195f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ITestClass testClass= testMethod.getTestClass();
1196f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Object[] instances = testClass.getInstances(true);
1197f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(Object instance: instances) {
1198f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeBeforeGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance);
1199f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1200f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1201f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1202f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    long maxTimeOut= -1; // 10 seconds
1203f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1204f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(IMethodWorker tmw : workers) {
1205f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      long mt= tmw.getMaxTimeOut();
1206f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(mt > maxTimeOut) {
1207f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        maxTimeOut= mt;
1208f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1209f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1210f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1211f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ThreadUtil.execute(workers, threadPoolSize, maxTimeOut, true);
1212f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1213f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1214f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Collect all the TestResults
1215f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    //
1216f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<ITestResult> result = new ArrayList<ITestResult>();
1217f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (IMethodWorker tmw : workers) {
1218f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      result.addAll(tmw.getTestResults());
1219f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1220f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1221f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(Object instance: instances) {
1222f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      invokeAfterGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance);
1223f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1224f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1225f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1226f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1227f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1228f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1229f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param testMethod
1230f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param testClass
1231f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return dependencies have been run successfully
1232f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1233f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean checkDependencies(ITestNGMethod testMethod, ITestClass testClass, ITestNGMethod[] allTestMethods)
1234f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  {
1235f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean result= true;
1236f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1237f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If this method is marked alwaysRun, no need to check for its
1238f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // dependencies
1239f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (testMethod.isAlwaysRun()) {
1240f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return true;
1241f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1242f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1243f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Any missing group?
1244f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if (testMethod.getMissingGroup() != null) {
1245f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return false;
1246f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1247f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1248f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If this method depends on groups, collect all the methods that
1249f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // belong to these groups and make sure they have been run successfully
1250f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(dependsOnGroups(testMethod)) {
1251f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      String[] groupsDependedUpon= testMethod.getGroupsDependedUpon();
1252f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1253f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // Get all the methods that belong to the group depended upon
1254f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for(int i= 0; i < groupsDependedUpon.length; i++) {
1255f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        ITestNGMethod[] methods =
1256f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          MethodHelper.findMethodsThatBelongToGroup(testMethod,
1257f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              m_testContext.getAllTestMethods(),
1258f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust              groupsDependedUpon[i]);
1259f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1260f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        result = result && haveBeenRunSuccessfully(methods);
1261f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1262f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    } // depends on groups
1263f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1264f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // If this method depends on other methods, make sure all these other
1265f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // methods have been run successfully
1266f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(dependsOnMethods(testMethod)) {
1267f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      ITestNGMethod[] methods =
1268f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        MethodHelper.findMethodsNamed(testMethod.getMethod().getName(),
1269f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       allTestMethods,
1270f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                                                       testMethod.getMethodsDependedUpon());
1271f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1272f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      result= result && haveBeenRunSuccessfully(methods);
1273f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1274f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1275f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1276f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1277f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1278f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1279f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if all the methods have been run successfully
1280f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1281f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean haveBeenRunSuccessfully(ITestNGMethod[] methods) {
1282f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    // Make sure the method has been run successfully
1283f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(int j= 0; j < methods.length; j++) {
1284f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      Set<ITestResult> results= m_notifier.getPassedTests(methods[j]);
1285f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1286f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      // If no results were returned, then these tests didn't pass
1287f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if (results == null || results.size() == 0) return false;
1288f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1289f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      for (ITestResult result : results) {
1290f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        if(!result.isSuccess()) {
1291f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          return false;
1292f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1293f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1294f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1295f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1296f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return true;
1297f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1298f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1299f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1300f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * An exception was thrown by the test, determine if this method
1301f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * should be marked as a failure or as failure_but_within_successPercentage
1302f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1303f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void handleException(Throwable throwable,
1304f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               ITestNGMethod testMethod,
1305f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               ITestResult testResult,
1306f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust                               int failureCount) {
1307f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    testResult.setThrowable(throwable);
1308f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int successPercentage= testMethod.getSuccessPercentage();
1309f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    int invocationCount= testMethod.getInvocationCount();
1310f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    float numberOfTestsThatCanFail= ((100 - successPercentage) * invocationCount) / 100;
1311f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1312f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(failureCount < numberOfTestsThatCanFail) {
1313f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.SUCCESS_PERCENTAGE_FAILURE);
1314f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1315f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    else {
1316f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      testResult.setStatus(ITestResult.FAILURE);
1317f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1318f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1319f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1320f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1321f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1322f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param ite The exception that was just thrown
1323f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @param expectedExceptions The list of expected exceptions for this
1324f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * test method
1325f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if the exception that was just thrown is part of the
1326f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * expected exceptions
1327f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1328f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean isExpectedException(Throwable ite, Class<?>[] exceptions) {
1329f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == exceptions) {
1330f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return false;
1331f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1332f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1333f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Class<?> realExceptionClass= ite.getClass();
1334f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1335f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(int i= 0; i < exceptions.length; i++) {
1336f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(exceptions[i].isAssignableFrom(realExceptionClass)) {
1337f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        return true;
1338f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1339f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1340f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1341f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return false;
1342f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1343f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1344f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1345f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return Only the ITestNGMethods applicable for this testClass
1346f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1347f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ITestNGMethod[] filterMethods(IClass testClass, ITestNGMethod[] methods) {
1348f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<ITestNGMethod> vResult= new ArrayList<ITestNGMethod>();
1349f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1350f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(ITestNGMethod tm : methods) {
1351f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(tm.canRunFromClass(testClass)) {
1352f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        log(9, "Keeping method " + tm + " for class " + testClass);
1353f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        vResult.add(tm);
1354f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1355f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
1356f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        log(9, "Filtering out method " + tm + " for class " + testClass);
1357f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1358f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1359f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1360f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ITestNGMethod[] result= vResult.toArray(new ITestNGMethod[vResult.size()]);
1361f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1362f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1363f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1364f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1365f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private ITestNGMethod[] filterMethodsUnique(IClass testClass, ITestNGMethod[] methods) {
1366f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    if(null == testClass) {
1367f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return methods;
1368f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1369f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1370f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<ITestNGMethod> vResult= new ArrayList<ITestNGMethod>();
1371f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1372f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(ITestNGMethod tm : methods) {
1373f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(null == testClass) {
1374f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        testClass= tm.getTestClass();
1375f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1376f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1377f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(tm.getTestClass().getName().equals(testClass.getName())) {
1378f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        log(9, "        Keeping method " + tm + " for class " + testClass);
1379f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1380f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        vResult.add(tm);
1381f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1382f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      else {
1383f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        log(9, "        Filtering out method " + tm + " for class " + testClass);
1384f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1385f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1386f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1387f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    ITestNGMethod[] result= vResult.toArray(new ITestNGMethod[vResult.size()]);
1388f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1389f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1390f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1391f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1392f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1393f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if this method depends on certain groups.
1394f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1395f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean dependsOnGroups(ITestNGMethod tm) {
1396f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] groups= tm.getGroupsDependedUpon();
1397f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean result= (null != groups) && (groups.length > 0);
1398f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1399f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1400f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1401f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1402f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  /**
1403f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   * @return true if this method depends on certain groups.
1404f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust   */
1405f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private boolean dependsOnMethods(ITestNGMethod tm) {
1406f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    String[] methods= tm.getMethodsDependedUpon();
1407f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    boolean result= (null != methods) && (methods.length > 0);
1408f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1409f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    return result;
1410f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1411f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1412f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void runConfigurationListeners(ITestResult tr) {
1413f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for(IConfigurationListener icl: m_notifier.getConfigurationListeners()) {
1414f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      switch(tr.getStatus()) {
1415f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SKIP:
1416f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          icl.onConfigurationSkip(tr);
1417f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1418f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.FAILURE:
1419f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          icl.onConfigurationFailure(tr);
1420f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1421f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SUCCESS:
1422f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          icl.onConfigurationSuccess(tr);
1423f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1424f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1425f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1426f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1427f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1428f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void runTestListeners(ITestResult tr) {
1429f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    runTestListeners(tr, m_notifier.getTestListeners());
1430f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1431f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1432f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  // TODO: move this from here as it is directly called from TestNG
1433f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  public static void runTestListeners(ITestResult tr, List<ITestListener> listeners) {
1434f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    for (ITestListener itl : listeners) {
1435f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      switch(tr.getStatus()) {
1436f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SKIP: {
1437f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestSkipped(tr);
1438f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1439f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1440f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SUCCESS_PERCENTAGE_FAILURE: {
1441f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestFailedButWithinSuccessPercentage(tr);
1442f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1443f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1444f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.FAILURE: {
1445f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestFailure(tr);
1446f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1447f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1448f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.SUCCESS: {
1449f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestSuccess(tr);
1450f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1451f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1452f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1453f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        case ITestResult.STARTED: {
1454f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          itl.onTestStart(tr);
1455f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          break;
1456f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1457f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1458f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        default: {
1459f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          assert false : "UNKNOWN STATUS:" + tr;
1460f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        }
1461f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1462f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1463f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1464f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1465f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private static void ppp(String s) {
1466f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    System.out.println("[Invoker]" + s);
1467f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1468f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1469f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private void log(int level, String s) {
1470f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    Utils.log("Invoker " + Thread.currentThread().hashCode(), level, s);
1471f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1472f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1473f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private class DataTestMethodWorker implements IMethodWorker {
1474f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final Object[] m_instances;
1475f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final ITestNGMethod m_testMethod;
1476f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final ITestNGMethod[] m_beforeMethods;
1477f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final ITestNGMethod[] m_afterMethods;
1478f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final ConfigurationGroupMethods m_groupMethods;
1479f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final Object[] m_parameters;
1480f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final XmlSuite m_suite;
1481f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final Map<String, String> m_allParameterNames;
1482f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1483f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    List<ITestResult> m_results;
1484f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1485f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public DataTestMethodWorker(Object[] instances,
1486f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        ITestNGMethod testMethod,
1487f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Object[] params,
1488f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        ITestNGMethod[] befores,
1489f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        ITestNGMethod[] afters,
1490f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        ConfigurationGroupMethods groupMethods,
1491f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        XmlSuite suite,
1492f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        Map<String, String> paramNames) {
1493f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_instances= instances;
1494f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_testMethod= testMethod;
1495f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_parameters= params;
1496f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_beforeMethods= befores;
1497f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_afterMethods= afters;
1498f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_groupMethods= groupMethods;
1499f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_suite= suite;
1500f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_allParameterNames= paramNames;
1501f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1502f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1503f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public long getMaxTimeOut() {
1504f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return 0;
1505f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1506f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1507f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public void run() {
1508f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      m_results= invokeTestMethod(m_instances,
1509f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_testMethod,
1510f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_parameters,
1511f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_suite,
1512f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_allParameterNames,
1513f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_testMethod.getTestClass(),
1514f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_beforeMethods,
1515f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_afterMethods,
1516f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust          m_groupMethods);
1517f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1518f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1519f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public List<ITestResult> getTestResults() {
1520f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return m_results;
1521f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1522f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1523f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1524f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  private static class ParameterBag {
1525f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final Iterator<Object[]> parameterValues;
1526f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    final List<ITestResult> errorResults= new ArrayList<ITestResult>();
1527f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1528f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public ParameterBag(Iterator<Object[]> params, TestResult tr) {
1529f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      parameterValues= params;
1530f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      if(tr != null) {
1531f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust        errorResults.add(tr);
1532f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      }
1533f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1534f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust
1535f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    public boolean hasErrors() {
1536f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust      return !errorResults.isEmpty();
1537f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust    }
1538f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust  }
1539f17a79b6a57f282e5cc0fbe741e73309e217976eCédric Beust}
1540