org.testng.internal.TestMethodWorker Maven / Gradle / Ivy
Show all versions of testng Show documentation
package org.testng.internal;
import org.testng.ClassMethodMap;
import org.testng.IClassListener;
import org.testng.IMethodInstance;
import org.testng.ITestClass;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.collections.Lists;
import org.testng.collections.Sets;
import org.testng.internal.ConfigMethodArguments.Builder;
import org.testng.thread.IWorker;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* FIXME: reduce contention when this class is used through parallel invocation due to
* invocationCount and threadPoolSize by not invoking the @BeforeClass and @AfterClass which are
* already invoked on the original method.
*
* This class implements Runnable and will invoke the ITestMethod passed in its constructor on
* its run() method.
*/
public class TestMethodWorker implements IWorker {
// Map of the test methods and their associated instances
// It has to be a set because the same method can be passed several times
// and associated to a different instance
private List m_methodInstances;
private final Map m_parameters;
private List m_testResults = Lists.newArrayList();
private final ConfigurationGroupMethods m_groupMethods;
private final ClassMethodMap m_classMethodMap;
private final ITestContext m_testContext;
private final List m_listeners;
private long currentThreadId;
private long threadIdToRunOn = -1;
private boolean completed = true;
private final ITestInvoker m_testInvoker;
private final IConfigInvoker m_configInvoker;
public TestMethodWorker(
ITestInvoker testInvoker,
IConfigInvoker configInvoker,
List testMethods,
Map parameters,
ConfigurationGroupMethods groupMethods,
ClassMethodMap classMethodMap,
ITestContext testContext,
List listeners) {
this.m_testInvoker = testInvoker;
this.m_configInvoker = configInvoker;
m_methodInstances = testMethods;
m_parameters = parameters;
m_groupMethods = groupMethods;
m_classMethodMap = classMethodMap;
m_testContext = testContext;
m_listeners = listeners;
}
/**
* Retrieves the maximum specified timeout of all ITestNGMethods to be run.
*
* @return the max timeout or 0 if no timeout was specified
*/
@Override
public long getTimeOut() {
long result = 0;
for (IMethodInstance mi : m_methodInstances) {
ITestNGMethod tm = mi.getMethod();
if (tm.getTimeOut() > result) {
result = tm.getTimeOut();
}
}
return result;
}
@Override
public String toString() {
StringBuilder result =
new StringBuilder(
"[Worker thread:"
+ Thread.currentThread().getId()
+ " priority:"
+ getPriority()
+ " ");
for (IMethodInstance m : m_methodInstances) {
result.append(m.getMethod()).append(" ");
}
result.append("]");
return result.toString();
}
/**
* Run all the ITestNGMethods passed in through the constructor.
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
this.currentThreadId = Thread.currentThread().getId();
if (RuntimeBehavior.enforceThreadAffinity()
&& doesTaskHavePreRequistes()
&& currentThreadId != threadIdToRunOn) {
completed = false;
return;
}
for (IMethodInstance testMthdInst : m_methodInstances) {
ITestNGMethod testMethod = testMthdInst.getMethod();
if (canInvokeBeforeClassMethods()) {
synchronized (testMethod.getInstance()) {
invokeBeforeClassMethods(testMethod.getTestClass(), testMthdInst);
}
}
// Invoke test method
try {
invokeTestMethods(testMethod, testMthdInst.getInstance());
} finally {
invokeAfterClassMethods(testMethod.getTestClass(), testMthdInst);
}
}
}
private boolean doesTaskHavePreRequistes() {
return threadIdToRunOn != -1;
}
protected void invokeTestMethods(ITestNGMethod tm, Object instance) {
// Potential bug here: we look up the method index of tm among all
// the test methods (not very efficient) but if this method appears
// several times and these methods are run in parallel, the results
// are unpredictable... Need to think about this more (and make it
// more efficient)
List testResults =
m_testInvoker.invokeTestMethods(tm, m_groupMethods, instance, m_testContext);
if (testResults != null) {
m_testResults.addAll(testResults);
}
}
private boolean canInvokeBeforeClassMethods() {
return m_classMethodMap != null;
}
/** Invoke the @BeforeClass methods if not done already */
protected void invokeBeforeClassMethods(ITestClass testClass, IMethodInstance mi) {
Map> invokedBeforeClassMethods =
m_classMethodMap.getInvokedBeforeClassMethods();
Set