1b1c182d51b05a40ac5350e562503a94d024a7c80nullinpackage org.testng.internal;
2b1c182d51b05a40ac5350e562503a94d024a7c80nullin
324e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhinimport org.testng.IConfigurable;
4b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.IConfigureCallBack;
5b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.IHookCallBack;
624e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhinimport org.testng.IHookable;
7b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.ITestContext;
8b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.ITestNGMethod;
9b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.ITestResult;
10b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.TestNGException;
11ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beustimport org.testng.annotations.DataProvider;
12b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.collections.Lists;
13b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.internal.annotations.IAnnotationFinder;
142a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhinimport org.testng.internal.collections.Pair;
15b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.internal.thread.IExecutor;
16b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.internal.thread.IFutureResult;
17b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.internal.thread.ThreadExecutionException;
18b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.internal.thread.ThreadTimeoutException;
19b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport org.testng.internal.thread.ThreadUtil;
202c23fd8d5624a9c06eee5e06721b79d96c421fe5Julien Herrimport org.testng.xml.XmlSuite;
21b1c182d51b05a40ac5350e562503a94d024a7c80nullin
222a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhinimport java.lang.reflect.Constructor;
23b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport java.lang.reflect.InvocationTargetException;
24b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport java.lang.reflect.Method;
25b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport java.lang.reflect.Modifier;
262a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhinimport java.util.ArrayList;
272a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhinimport java.util.Collection;
28b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport java.util.Iterator;
29b1c182d51b05a40ac5350e562503a94d024a7c80nullinimport java.util.List;
30b1c182d51b05a40ac5350e562503a94d024a7c80nullin
31b1c182d51b05a40ac5350e562503a94d024a7c80nullin/**
32b1c182d51b05a40ac5350e562503a94d024a7c80nullin * Collections of helper methods to help deal with invocation of TestNG methods
330f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin *
340f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin * @author Cedric Beust <cedric@beust.com>
350f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin * @author nullin <nalin.makar * gmail.com>
36b1c182d51b05a40ac5350e562503a94d024a7c80nullin *
37b1c182d51b05a40ac5350e562503a94d024a7c80nullin */
38b1c182d51b05a40ac5350e562503a94d024a7c80nullinpublic class MethodInvocationHelper {
39b1c182d51b05a40ac5350e562503a94d024a7c80nullin
40b1c182d51b05a40ac5350e562503a94d024a7c80nullin  protected static Object invokeMethod(Method thisMethod, Object instance, Object[] parameters)
4130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      throws InvocationTargetException, IllegalAccessException {
424438e4fa82ea3d7d8623d11156657d119cddaa14Cédric Beust    Utils.checkInstanceOrStatic(instance, thisMethod);
434438e4fa82ea3d7d8623d11156657d119cddaa14Cédric Beust
44b1c182d51b05a40ac5350e562503a94d024a7c80nullin    // TESTNG-326, allow IObjectFactory to load from non-standard classloader
4530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust    // If the instance has a different classloader, its class won't match the
4630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust    // method's class
474438e4fa82ea3d7d8623d11156657d119cddaa14Cédric Beust    if (instance == null || !thisMethod.getDeclaringClass().isAssignableFrom(instance.getClass())) {
48b1c182d51b05a40ac5350e562503a94d024a7c80nullin      // for some reason, we can't call this method on this class
49b1c182d51b05a40ac5350e562503a94d024a7c80nullin      // is it static?
50b1c182d51b05a40ac5350e562503a94d024a7c80nullin      boolean isStatic = Modifier.isStatic(thisMethod.getModifiers());
51b1c182d51b05a40ac5350e562503a94d024a7c80nullin      if (!isStatic) {
52b1c182d51b05a40ac5350e562503a94d024a7c80nullin        // not static, so grab a method with the same name and signature in this case
53b1c182d51b05a40ac5350e562503a94d024a7c80nullin        Class<?> clazz = instance.getClass();
54b1c182d51b05a40ac5350e562503a94d024a7c80nullin        try {
55b1c182d51b05a40ac5350e562503a94d024a7c80nullin          thisMethod = clazz.getMethod(thisMethod.getName(), thisMethod.getParameterTypes());
56b1c182d51b05a40ac5350e562503a94d024a7c80nullin        } catch (Exception e) {
57b1c182d51b05a40ac5350e562503a94d024a7c80nullin          // ignore, the method may be private
58b1c182d51b05a40ac5350e562503a94d024a7c80nullin          boolean found = false;
59b1c182d51b05a40ac5350e562503a94d024a7c80nullin          for (; clazz != null; clazz = clazz.getSuperclass()) {
60b1c182d51b05a40ac5350e562503a94d024a7c80nullin            try {
6130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust              thisMethod = clazz.getDeclaredMethod(thisMethod.getName(),
6230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust                  thisMethod.getParameterTypes());
63b1c182d51b05a40ac5350e562503a94d024a7c80nullin              found = true;
64b1c182d51b05a40ac5350e562503a94d024a7c80nullin              break;
6530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust            } catch (Exception e2) {
6630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust            }
67b1c182d51b05a40ac5350e562503a94d024a7c80nullin          }
68b1c182d51b05a40ac5350e562503a94d024a7c80nullin          if (!found) {
6930b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust            // should we assert here? Or just allow it to fail on invocation?
70b1c182d51b05a40ac5350e562503a94d024a7c80nullin            if (thisMethod.getDeclaringClass().getName().equals(instance.getClass().getName())) {
7130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust              throw new RuntimeException("Can't invoke method " + thisMethod
7230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust                  + ", probably due to classloader mismatch");
73b1c182d51b05a40ac5350e562503a94d024a7c80nullin            }
7430b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust            throw new RuntimeException("Can't invoke method " + thisMethod
7530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust                + " on this instance of " + instance.getClass() + " due to class mismatch");
76b1c182d51b05a40ac5350e562503a94d024a7c80nullin          }
77b1c182d51b05a40ac5350e562503a94d024a7c80nullin        }
78b1c182d51b05a40ac5350e562503a94d024a7c80nullin      }
79b1c182d51b05a40ac5350e562503a94d024a7c80nullin    }
800f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
8161a0a8a2e056dd41e02efdef372de49d2996b67aCédric Beust    synchronized(thisMethod) {
8261a0a8a2e056dd41e02efdef372de49d2996b67aCédric Beust      if (! Modifier.isPublic(thisMethod.getModifiers())) {
83b1c182d51b05a40ac5350e562503a94d024a7c80nullin        thisMethod.setAccessible(true);
84b1c182d51b05a40ac5350e562503a94d024a7c80nullin      }
85b1c182d51b05a40ac5350e562503a94d024a7c80nullin    }
8661a0a8a2e056dd41e02efdef372de49d2996b67aCédric Beust    return thisMethod.invoke(instance, parameters);
87b1c182d51b05a40ac5350e562503a94d024a7c80nullin  }
88b1c182d51b05a40ac5350e562503a94d024a7c80nullin
8930b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust  protected static Iterator<Object[]> invokeDataProvider(Object instance, Method dataProvider,
9030b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      ITestNGMethod method, ITestContext testContext, Object fedInstance,
9130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      IAnnotationFinder annotationFinder) {
9224e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin    Iterator<Object[]> result;
932a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin    final ConstructorOrMethod com = method.getConstructorOrMethod();
940f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
95b1c182d51b05a40ac5350e562503a94d024a7c80nullin    // If it returns an Object[][], convert it to an Iterable<Object[]>
96b1c182d51b05a40ac5350e562503a94d024a7c80nullin    try {
97b1c182d51b05a40ac5350e562503a94d024a7c80nullin      List<Object> lParameters = Lists.newArrayList();
980f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
99b1c182d51b05a40ac5350e562503a94d024a7c80nullin      // Go through all the parameters declared on this Data Provider and
100b1c182d51b05a40ac5350e562503a94d024a7c80nullin      // make sure we have at most one Method and one ITestContext.
101b1c182d51b05a40ac5350e562503a94d024a7c80nullin      // Anything else is an error
102b1c182d51b05a40ac5350e562503a94d024a7c80nullin      Class<?>[] parameterTypes = dataProvider.getParameterTypes();
1030f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
10410c223b7aa6bf34778079bb5ee1a494c83cd1239Ryan Schmitt      final Collection<Pair<Integer, Class<?>>> unresolved = new ArrayList<>(parameterTypes.length);
105b1c182d51b05a40ac5350e562503a94d024a7c80nullin      int i = 0;
106b1c182d51b05a40ac5350e562503a94d024a7c80nullin      for (Class<?> cls : parameterTypes) {
107b1c182d51b05a40ac5350e562503a94d024a7c80nullin        boolean isTestInstance = annotationFinder.hasTestInstance(dataProvider, i++);
108b1c182d51b05a40ac5350e562503a94d024a7c80nullin        if (cls.equals(Method.class)) {
1092a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin          lParameters.add(com.getMethod());
1102a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        } else if (cls.equals(Constructor.class)) {
1112a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin          lParameters.add(com.getConstructor());
1122a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        } else if (cls.equals(ConstructorOrMethod.class)) {
1132a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin          lParameters.add(com);
1142a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        } else if (cls.equals(ITestNGMethod.class)) {
1152a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin          lParameters.add(method);
11630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust        } else if (cls.equals(ITestContext.class)) {
117b1c182d51b05a40ac5350e562503a94d024a7c80nullin          lParameters.add(testContext);
11830b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust        } else if (isTestInstance) {
119b1c182d51b05a40ac5350e562503a94d024a7c80nullin          lParameters.add(fedInstance);
1202a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        } else {
1212a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin          unresolved.add(new Pair<Integer, Class<?>>(i, cls));
1222a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        }
1232a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin      }
1242a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin      if (!unresolved.isEmpty()) {
1252a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        final StringBuilder sb = new StringBuilder();
1262a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        sb.append("Some DataProvider ").append(dataProvider).append(" parameters unresolved: ");
1272a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        for (Pair<Integer, Class<?>> pair : unresolved) {
1282a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin          sb.append(" at ").append(pair.first()).append(" type ").append(pair.second()).append("\n");
129b1c182d51b05a40ac5350e562503a94d024a7c80nullin        }
1302a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin        throw new TestNGException(sb.toString());
131b1c182d51b05a40ac5350e562503a94d024a7c80nullin      }
1322a4d14e870d4cf6b6e4800ffd72c7d46deefc473Vladislav Rassokhin
133b1c182d51b05a40ac5350e562503a94d024a7c80nullin      Object[] parameters = lParameters.toArray(new Object[lParameters.size()]);
1340f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
13530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      Class<?> returnType = dataProvider.getReturnType();
136b1c182d51b05a40ac5350e562503a94d024a7c80nullin      if (Object[][].class.isAssignableFrom(returnType)) {
137ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust        Object[][] originalResult = (Object[][]) invokeMethod(dataProvider, instance, parameters);
138ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust
139ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust        // If the data provider is restricting the indices to return, filter them out
140ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust        int[] indices = dataProvider.getAnnotation(DataProvider.class).indices();
141ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust        Object[][] oResult;
142ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust        if (indices.length > 0) {
143ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust          oResult = new Object[indices.length][];
144ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust          for (int j = 0; j < indices.length; j++) {
145ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust            oResult[j] = originalResult[indices[j]];
146ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust          }
147ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust        } else {
148ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust          oResult = originalResult;
149ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust        }
150ed9cafaaad9cf9da7940ad1da9437f27cb85438dCédric Beust
151b1c182d51b05a40ac5350e562503a94d024a7c80nullin        method.setParameterInvocationCount(oResult.length);
152b1c182d51b05a40ac5350e562503a94d024a7c80nullin        result = MethodHelper.createArrayIterator(oResult);
15330b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      } else if (Iterator.class.isAssignableFrom(returnType)) {
15424e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin        // Already an Iterator<Object[]>, assign it directly
15530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust        result = (Iterator<Object[]>) invokeMethod(dataProvider, instance, parameters);
15630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      } else {
15730b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust        throw new TestNGException("Data Provider " + dataProvider + " must return"
15830b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust            + " either Object[][] or Iterator<Object>[], not " + returnType);
159b1c182d51b05a40ac5350e562503a94d024a7c80nullin      }
160a3f78c5debcd03e7755f5ff2956a6f325e41d0b7Ryan Schmitt    } catch (InvocationTargetException | IllegalAccessException e) {
16130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      // Don't throw TestNGException here or this test won't be reported as a
16230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      // skip or failure
163f5fc1732fe39aae26224f00a23273fe3e9929398Cédric Beust      throw new RuntimeException(e.getCause());
164b1c182d51b05a40ac5350e562503a94d024a7c80nullin    }
1650f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
166b1c182d51b05a40ac5350e562503a94d024a7c80nullin    return result;
167b1c182d51b05a40ac5350e562503a94d024a7c80nullin  }
168b1c182d51b05a40ac5350e562503a94d024a7c80nullin
169b1c182d51b05a40ac5350e562503a94d024a7c80nullin  /**
170b1c182d51b05a40ac5350e562503a94d024a7c80nullin   * Invokes the <code>run</code> method of the <code>IHookable</code>.
171b1c182d51b05a40ac5350e562503a94d024a7c80nullin   *
17230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * @param testInstance
17330b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   *          the instance to invoke the method in
17430b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * @param parameters
17530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   *          the parameters to be passed to <code>IHookCallBack</code>
17630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * @param thisMethod
17730b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   *          the method to be invoked through the <code>IHookCallBack</code>
17830b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * @param testResult
17930b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   *          the current <code>ITestResult</code> passed to
18030b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   *          <code>IHookable.run</code>
181b1c182d51b05a40ac5350e562503a94d024a7c80nullin   * @throws NoSuchMethodException
182b1c182d51b05a40ac5350e562503a94d024a7c80nullin   * @throws IllegalAccessException
183b1c182d51b05a40ac5350e562503a94d024a7c80nullin   * @throws InvocationTargetException
18430b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * @throws Throwable
18530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   *           thrown if the reflective call to
18630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   *           <tt>thisMethod</code> results in an exception
187b1c182d51b05a40ac5350e562503a94d024a7c80nullin   */
18830b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust  protected static void invokeHookable(final Object testInstance, final Object[] parameters,
18924e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin                                       final IHookable hookable, final Method thisMethod,
1908e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr                                       final ITestResult testResult) throws Throwable {
191b1c182d51b05a40ac5350e562503a94d024a7c80nullin    final Throwable[] error = new Throwable[1];
1920f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
193b1c182d51b05a40ac5350e562503a94d024a7c80nullin    IHookCallBack callback = new IHookCallBack() {
194b1c182d51b05a40ac5350e562503a94d024a7c80nullin      @Override
195b1c182d51b05a40ac5350e562503a94d024a7c80nullin      public void runTestMethod(ITestResult tr) {
196b1c182d51b05a40ac5350e562503a94d024a7c80nullin        try {
197b1c182d51b05a40ac5350e562503a94d024a7c80nullin          invokeMethod(thisMethod, testInstance, parameters);
19830b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust        } catch (Throwable t) {
19930b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust          error[0] = t;
20030b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust          tr.setThrowable(t); // make Throwable available to IHookable
20130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust        }
20230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      }
2030f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
204b1c182d51b05a40ac5350e562503a94d024a7c80nullin      @Override
205b1c182d51b05a40ac5350e562503a94d024a7c80nullin      public Object[] getParameters() {
206b1c182d51b05a40ac5350e562503a94d024a7c80nullin        return parameters;
207b1c182d51b05a40ac5350e562503a94d024a7c80nullin      }
208b1c182d51b05a40ac5350e562503a94d024a7c80nullin    };
20924e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin    hookable.run(callback, testResult);
210b1c182d51b05a40ac5350e562503a94d024a7c80nullin    if (error[0] != null) {
211b1c182d51b05a40ac5350e562503a94d024a7c80nullin      throw error[0];
212b1c182d51b05a40ac5350e562503a94d024a7c80nullin    }
213b1c182d51b05a40ac5350e562503a94d024a7c80nullin  }
214b1c182d51b05a40ac5350e562503a94d024a7c80nullin
215b1c182d51b05a40ac5350e562503a94d024a7c80nullin  /**
21630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * Invokes a method on a separate thread in order to allow us to timeout the
21730b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * invocation. It uses as implementation an <code>Executor</code> and a
21830b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   * <code>CountDownLatch</code>.
21930b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust   */
22030b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust  protected static void invokeWithTimeout(ITestNGMethod tm, Object instance,
22130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      Object[] parameterValues, ITestResult testResult)
22230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      throws InterruptedException, ThreadExecutionException {
2238e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr    invokeWithTimeout(tm, instance, parameterValues, testResult, null);
2248e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr  }
2258e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr
2268e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr  protected static void invokeWithTimeout(ITestNGMethod tm, Object instance,
2278e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr      Object[] parameterValues, ITestResult testResult, IHookable hookable)
2288e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr      throws InterruptedException, ThreadExecutionException {
2292c23fd8d5624a9c06eee5e06721b79d96c421fe5Julien Herr    if (ThreadUtil.isTestNGThread() && testResult.getTestContext().getCurrentXmlTest().getParallel() != XmlSuite.ParallelMode.TESTS) {
23030b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      // We are already running in our own executor, don't create another one (or we will
23130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      // lose the time out of the enclosing executor).
2328e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr      invokeWithTimeoutWithNoExecutor(tm, instance, parameterValues, testResult, hookable);
23330b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust    } else {
2348e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr      invokeWithTimeoutWithNewExecutor(tm, instance, parameterValues, testResult, hookable);
235349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    }
23630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust  }
2370f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
23830b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust  private static void invokeWithTimeoutWithNoExecutor(ITestNGMethod tm, Object instance,
2398e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr      Object[] parameterValues, ITestResult testResult, IHookable hookable) {
2400f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2418e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr    InvokeMethodRunnable imr = new InvokeMethodRunnable(tm, instance, parameterValues, hookable, testResult);
242349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    try {
243349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      imr.run();
244349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      testResult.setStatus(ITestResult.SUCCESS);
24530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust    } catch (Exception ex) {
246349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      testResult.setThrowable(ex.getCause());
247349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      testResult.setStatus(ITestResult.FAILURE);
248349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    }
249349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust  }
250349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust
25130b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust  private static void invokeWithTimeoutWithNewExecutor(ITestNGMethod tm, Object instance,
2528e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr      Object[] parameterValues, ITestResult testResult, IHookable hookable)
253349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      throws InterruptedException, ThreadExecutionException {
25424e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin    IExecutor exec = ThreadUtil.createExecutor(1, tm.getMethodName());
255349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust
2568e84be5f48c104aa57cd9de8db3dd4d7a676040cJulien Herr    InvokeMethodRunnable imr = new InvokeMethodRunnable(tm, instance, parameterValues, hookable, testResult);
257349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    IFutureResult future = exec.submitRunnable(imr);
258349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    exec.shutdown();
259349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    long realTimeOut = MethodHelper.calculateTimeOut(tm);
260349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    boolean finished = exec.awaitTermination(realTimeOut);
261349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust
26230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust    if (!finished) {
263349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      exec.stopNow();
264349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      ThreadTimeoutException exception = new ThreadTimeoutException("Method "
26530b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust          + tm.getClass().getName() + "." + tm.getMethodName() + "()"
26630b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust          + " didn't finish within the time-out " + realTimeOut);
267349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      exception.setStackTrace(exec.getStackTraces()[0]);
268349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      testResult.setThrowable(exception);
269349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      testResult.setStatus(ITestResult.FAILURE);
27030b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust    } else {
27124e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin      Utils.log("Invoker " + Thread.currentThread().hashCode(), 3, "Method " + tm.getMethodName()
27230b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust          + " completed within the time-out " + tm.getTimeOut());
273349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust
274349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      // We don't need the result from the future but invoking get() on it
275349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      // will trigger the exception that was thrown, if any
276349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust      future.get();
27730b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      // done.await();
278349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust
27930b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust      testResult.setStatus(ITestResult.SUCCESS); // if no exception till here
28030b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust                                                 // than SUCCESS
281349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust    }
282349a0501482e3fada78e74a70eea8b8585bca308Cédric Beust  }
283b1c182d51b05a40ac5350e562503a94d024a7c80nullin
28430b5dbacace7283ae6ee0bc2af4ecd647eca75f7Cédric Beust  protected static void invokeConfigurable(final Object instance, final Object[] parameters,
28524e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin                                           final IConfigurable configurableInstance, final Method thisMethod,
28624e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin                                           final ITestResult testResult) throws Throwable {
287b1c182d51b05a40ac5350e562503a94d024a7c80nullin    final Throwable[] error = new Throwable[1];
2880f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
289b1c182d51b05a40ac5350e562503a94d024a7c80nullin    IConfigureCallBack callback = new IConfigureCallBack() {
290b1c182d51b05a40ac5350e562503a94d024a7c80nullin      @Override
291b1c182d51b05a40ac5350e562503a94d024a7c80nullin      public void runConfigurationMethod(ITestResult tr) {
292b1c182d51b05a40ac5350e562503a94d024a7c80nullin        try {
293b1c182d51b05a40ac5350e562503a94d024a7c80nullin          invokeMethod(thisMethod, instance, parameters);
294b1c182d51b05a40ac5350e562503a94d024a7c80nullin        } catch (Throwable t) {
295b1c182d51b05a40ac5350e562503a94d024a7c80nullin          error[0] = t;
296b1c182d51b05a40ac5350e562503a94d024a7c80nullin          tr.setThrowable(t); // make Throwable available to IConfigurable
297b1c182d51b05a40ac5350e562503a94d024a7c80nullin        }
298b1c182d51b05a40ac5350e562503a94d024a7c80nullin      }
2990f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
300b1c182d51b05a40ac5350e562503a94d024a7c80nullin      @Override
301b1c182d51b05a40ac5350e562503a94d024a7c80nullin      public Object[] getParameters() {
302b1c182d51b05a40ac5350e562503a94d024a7c80nullin        return parameters;
303b1c182d51b05a40ac5350e562503a94d024a7c80nullin      }
304b1c182d51b05a40ac5350e562503a94d024a7c80nullin    };
30524e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin    configurableInstance.run(callback, testResult);
306b1c182d51b05a40ac5350e562503a94d024a7c80nullin    if (error[0] != null) {
307b1c182d51b05a40ac5350e562503a94d024a7c80nullin      throw error[0];
308b1c182d51b05a40ac5350e562503a94d024a7c80nullin    }
309b1c182d51b05a40ac5350e562503a94d024a7c80nullin  }
310b1c182d51b05a40ac5350e562503a94d024a7c80nullin
31124e36c535b7d2b03c32562162d8b7d8e4fe5f354Vladislav Rassokhin}
312