org.testng.TestRunner Maven / Gradle / Ivy
Show all versions of testng Show documentation
package org.testng;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.BlockingQueue;
import org.testng.collections.ListMultiMap;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.collections.Sets;
import org.testng.internal.AbstractParallelWorker;
import org.testng.internal.Attributes;
import org.testng.internal.ClassInfoMap;
import org.testng.internal.ConfigMethodArguments;
import org.testng.internal.ConfigMethodArguments.Builder;
import org.testng.internal.ConfigurationGroupMethods;
import org.testng.internal.DefaultListenerFactory;
import org.testng.internal.DynamicGraphHelper;
import org.testng.internal.GroupsHelper;
import org.testng.internal.IConfiguration;
import org.testng.internal.IInvoker;
import org.testng.internal.ITestResultNotifier;
import org.testng.internal.InstanceCreator;
import org.testng.internal.InvokedMethod;
import org.testng.internal.Invoker;
import org.testng.internal.TestMethodComparator;
import org.testng.internal.MethodGroupsHelper;
import org.testng.internal.MethodHelper;
import org.testng.internal.ResultMap;
import org.testng.internal.RunInfo;
import org.testng.internal.Systematiser;
import org.testng.internal.TestListenerHelper;
import org.testng.internal.TestMethodWorker;
import org.testng.internal.TestNGClassFinder;
import org.testng.internal.TestNGMethodFinder;
import org.testng.internal.Utils;
import org.testng.internal.XmlMethodSelector;
import org.testng.internal.annotations.IAnnotationFinder;
import org.testng.thread.ITestNGThreadPoolExecutor;
import org.testng.thread.IThreadWorkerFactory;
import org.testng.thread.IWorker;
import org.testng.junit.IJUnitTestRunner;
import org.testng.log4testng.Logger;
import org.testng.util.Strings;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlInclude;
import org.testng.xml.XmlPackage;
import org.testng.xml.XmlTest;
import com.google.inject.Injector;
import com.google.inject.Module;
import javax.annotation.Nonnull;
import static org.testng.internal.MethodHelper.fixMethodsWithClass;
/** This class takes care of running one Test. */
public class TestRunner
implements ITestContext, ITestResultNotifier, IThreadWorkerFactory {
private static final String DEFAULT_PROP_OUTPUT_DIR = "test-output";
private static final Logger LOGGER = Logger.getLogger(TestRunner.class);
private final Comparator comparator;
private ISuite m_suite;
private XmlTest m_xmlTest;
private String m_testName;
private final GuiceHelper guiceHelper = new GuiceHelper(this);
private List m_testClassesFromXml = null;
private IInvoker m_invoker = null;
private IAnnotationFinder m_annotationFinder = null;
/** ITestListeners support. */
private List m_testListeners = Lists.newArrayList();
private Set m_configurationListeners = Sets.newHashSet();
private final Set visualisers = Sets.newHashSet();
private IConfigurationListener m_confListener = new ConfigurationListener();
private Collection m_invokedMethodListeners = Lists.newArrayList();
private final Map, IClassListener> m_classListeners =
Maps.newHashMap();
private final Map, IDataProviderListener>
m_dataProviderListeners;
/**
* All the test methods we found, associated with their respective classes. Note that these test
* methods might belong to different classes. We pick which ones to run at runtime.
*/
private ITestNGMethod[] m_allTestMethods = new ITestNGMethod[0];
// Information about this test run
private Date m_startDate = new Date();
private Date m_endDate = null;
/** A map to keep track of Class <-> IClass. */
private Map, ITestClass> m_classMap = Maps.newLinkedHashMap();
/** Where the reports will be created. */
private String m_outputDirectory = DEFAULT_PROP_OUTPUT_DIR;
// The XML method selector (groups/methods included/excluded in XML)
private XmlMethodSelector m_xmlMethodSelector = new XmlMethodSelector();
private static int m_verbose = 1;
//
// These next fields contain all the configuration methods found on this class.
// At initialization time, they just contain all the various @Configuration methods
// found in all the classes we are going to run. When comes the time to run them,
// only a subset of them are run: those that are enabled and belong on the same class as
// (or a parent of) the test class.
//
/** */
private ITestNGMethod[] m_beforeSuiteMethods = {};
private ITestNGMethod[] m_afterSuiteMethods = {};
private ITestNGMethod[] m_beforeXmlTestMethods = {};
private ITestNGMethod[] m_afterXmlTestMethods = {};
private List m_excludedMethods = Lists.newArrayList();
private ConfigurationGroupMethods m_groupMethods = null;
// Meta groups
private Map> m_metaGroups = Maps.newHashMap();
// All the tests that were run along with their result
private IResultMap m_passedTests = new ResultMap();
private IResultMap m_failedTests = new ResultMap();
private IResultMap m_failedButWithinSuccessPercentageTests = new ResultMap();
private IResultMap m_skippedTests = new ResultMap();
private RunInfo m_runInfo = new RunInfo();
// The host where this test was run, or null if run locally
private String m_host;
// Defined dynamically depending on
private List m_methodInterceptors;
private ClassMethodMap m_classMethodMap;
private TestNGClassFinder m_testClassFinder;
private IConfiguration m_configuration;
public enum PriorityWeight {
groupByInstance,
preserveOrder,
priority,
dependsOnGroups,
dependsOnMethods
}
protected TestRunner(
IConfiguration configuration,
ISuite suite,
XmlTest test,
String outputDirectory,
IAnnotationFinder finder,
boolean skipFailedInvocationCounts,
Collection invokedMethodListeners,
List classListeners,
Comparator comparator,
Map, IDataProviderListener> dataProviderListeners) {
this.comparator = comparator;
this.m_dataProviderListeners = Maps.newHashMap(dataProviderListeners);
init(
configuration,
suite,
test,
outputDirectory,
finder,
skipFailedInvocationCounts,
invokedMethodListeners,
classListeners);
}
public TestRunner(
IConfiguration configuration,
ISuite suite,
XmlTest test,
boolean skipFailedInvocationCounts,
Collection invokedMethodListeners,
List classListeners,
Comparator comparator) {
this.comparator = comparator;
this.m_dataProviderListeners = Collections.emptyMap();
init(
configuration,
suite,
test,
suite.getOutputDirectory(),
suite.getAnnotationFinder(),
skipFailedInvocationCounts,
invokedMethodListeners,
classListeners);
}
/**
* This constructor is used by testng-remote, any changes related to it please contact with
* testng-team.
*/
public TestRunner(
IConfiguration configuration,
ISuite suite,
XmlTest test,
boolean skipFailedInvocationCounts,
Collection invokedMethodListeners,
List classListeners) {
this.comparator = Systematiser.getComparator();
this.m_dataProviderListeners = Collections.emptyMap();
init(
configuration,
suite,
test,
suite.getOutputDirectory(),
suite.getAnnotationFinder(),
skipFailedInvocationCounts,
invokedMethodListeners,
classListeners);
}
private void init(
IConfiguration configuration,
ISuite suite,
XmlTest test,
String outputDirectory,
IAnnotationFinder annotationFinder,
boolean skipFailedInvocationCounts,
Collection invokedMethodListeners,
List classListeners) {
m_configuration = configuration;
m_xmlTest = test;
m_suite = suite;
m_testName = test.getName();
m_host = suite.getHost();
m_testClassesFromXml = test.getXmlClasses();
setVerbose(test.getVerbose());
boolean preserveOrder = test.getPreserveOrder();
IMethodInterceptor builtinInterceptor =
preserveOrder
? new PreserveOrderMethodInterceptor()
: new InstanceOrderingMethodInterceptor();
m_methodInterceptors = new ArrayList<>();
// Add the built in interceptor as the first interceptor. That way we let our users determine
// the final order
// by plugging in their own custom interceptors as well.
m_methodInterceptors.add(builtinInterceptor);
List m_packageNamesFromXml = getAllPackages();
for (XmlPackage xp : m_packageNamesFromXml) {
m_testClassesFromXml.addAll(xp.getXmlClasses());
}
m_annotationFinder = annotationFinder;
m_invokedMethodListeners = invokedMethodListeners;
m_classListeners.clear();
for (IClassListener classListener : classListeners) {
m_classListeners.put(classListener.getClass(), classListener);
}
m_invoker =
new Invoker(
m_configuration,
this,
this,
m_suite.getSuiteState(),
skipFailedInvocationCounts,
invokedMethodListeners,
classListeners,
m_dataProviderListeners.values());
if (test.getParallel() != null) {
log(
"Running the tests in '" + test.getName() + "' with parallel mode:" + test.getParallel());
}
setOutputDirectory(outputDirectory);
// Finish our initialization
init();
}
/**
* Returns all packages to use for the current test. This includes the test from the test
* suite. Never returns null.
*/
private List getAllPackages() {
final List allPackages = Lists.newArrayList();
final List suitePackages = this.m_xmlTest.getSuite().getPackages();
if (suitePackages != null) {
allPackages.addAll(suitePackages);
}
final List testPackages = this.m_xmlTest.getPackages();
if (testPackages != null) {
allPackages.addAll(testPackages);
}
return allPackages;
}
public IInvoker getInvoker() {
return m_invoker;
}
public ITestNGMethod[] getBeforeSuiteMethods() {
return m_beforeSuiteMethods;
}
public ITestNGMethod[] getAfterSuiteMethods() {
return m_afterSuiteMethods;
}
public ITestNGMethod[] getBeforeTestConfigurationMethods() {
return m_beforeXmlTestMethods;
}
public ITestNGMethod[] getAfterTestConfigurationMethods() {
return m_afterXmlTestMethods;
}
private void init() {
initMetaGroups(m_xmlTest);
initRunInfo(m_xmlTest);
// Init methods and class map
// JUnit behavior is different and doesn't need this initialization step
if (!m_xmlTest.isJUnit()) {
initMethods();
}
initListeners();
addConfigurationListener(m_confListener);
for (IConfigurationListener cl : m_configuration.getConfigurationListeners()) {
addConfigurationListener(cl);
}
}
private void initListeners() {
//
// Find all the listener factories and collect all the listeners requested in a
// @Listeners annotation.
//
Set> listenerClasses = Sets.newHashSet();
Class listenerFactoryClass = null;
for (IClass cls : getTestClasses()) {
Class realClass = cls.getRealClass();
TestListenerHelper.ListenerHolder listenerHolder =
TestListenerHelper.findAllListeners(realClass, m_annotationFinder);
if (listenerFactoryClass == null) {
listenerFactoryClass = listenerHolder.getListenerFactoryClass();
}
listenerClasses.addAll(listenerHolder.getListenerClasses());
}
if (listenerFactoryClass == null) {
listenerFactoryClass = DefaultListenerFactory.class;
}
//
// Now we have all the listeners collected from @Listeners and at most one
// listener factory collected from a class implementing ITestNGListenerFactory.
// Instantiate all the requested listeners.
//
ITestNGListenerFactory factory =
TestListenerHelper.createListenerFactory(m_testClassFinder, listenerFactoryClass);
// Instantiate all the listeners
for (Class c : listenerClasses) {
if (IClassListener.class.isAssignableFrom(c) && m_classListeners.containsKey(c)) {
continue;
}
ITestNGListener listener = factory.createListener(c);
addListener(listener);
}
}
/** Initialize meta groups */
private void initMetaGroups(XmlTest xmlTest) {
Map> metaGroups = xmlTest.getMetaGroups();
for (Map.Entry> entry : metaGroups.entrySet()) {
addMetaGroup(entry.getKey(), entry.getValue());
}
}
private void initRunInfo(final XmlTest xmlTest) {
// Groups
m_xmlMethodSelector.setIncludedGroups(createGroups(m_xmlTest.getIncludedGroups()));
m_xmlMethodSelector.setExcludedGroups(createGroups(m_xmlTest.getExcludedGroups()));
m_xmlMethodSelector.setScript(m_xmlTest.getScript());
// Methods
m_xmlMethodSelector.setXmlClasses(m_xmlTest.getXmlClasses());
m_runInfo.addMethodSelector(m_xmlMethodSelector, 10);
// Add user-specified method selectors (only class selectors, we can ignore
// script selectors here)
if (null != xmlTest.getMethodSelectors()) {
for (org.testng.xml.XmlMethodSelector selector : xmlTest.getMethodSelectors()) {
if (selector.getClassName() != null) {
IMethodSelector s = InstanceCreator.createSelector(selector);
m_runInfo.addMethodSelector(s, selector.getPriority());
}
}
}
}
private void initMethods() {
//
// Calculate all the methods we need to invoke
//
List beforeClassMethods = Lists.newArrayList();
List testMethods = Lists.newArrayList();
List afterClassMethods = Lists.newArrayList();
List beforeSuiteMethods = Lists.newArrayList();
List afterSuiteMethods = Lists.newArrayList();
List beforeXmlTestMethods = Lists.newArrayList();
List afterXmlTestMethods = Lists.newArrayList();
ClassInfoMap classMap = new ClassInfoMap(m_testClassesFromXml);
m_testClassFinder =
new TestNGClassFinder(
classMap, Maps.newHashMap(), m_configuration, this, m_dataProviderListeners);
ITestMethodFinder testMethodFinder =
new TestNGMethodFinder(m_runInfo, m_annotationFinder, comparator);
m_runInfo.setTestMethods(testMethods);
//
// Initialize TestClasses
//
IClass[] classes = m_testClassFinder.findTestClasses();
for (IClass ic : classes) {
// Create TestClass
ITestClass tc =
new TestClass(
ic,
testMethodFinder,
m_annotationFinder,
m_xmlTest,
classMap.getXmlClass(ic.getRealClass()), m_testClassFinder.getFactoryCreationFailedMessage());
m_classMap.put(ic.getRealClass(), tc);
}
//
// Calculate groups methods
//
Map> beforeGroupMethods =
MethodGroupsHelper.findGroupsMethods(m_classMap.values(), true);
Map> afterGroupMethods =
MethodGroupsHelper.findGroupsMethods(m_classMap.values(), false);
//
// Walk through all the TestClasses, store their method
// and initialize them with the correct ITestClass
//
for (ITestClass tc : m_classMap.values()) {
fixMethodsWithClass(tc.getTestMethods(), tc, testMethods);
fixMethodsWithClass(tc.getBeforeClassMethods(), tc, beforeClassMethods);
fixMethodsWithClass(tc.getBeforeTestMethods(), tc, null);
fixMethodsWithClass(tc.getAfterTestMethods(), tc, null);
fixMethodsWithClass(tc.getAfterClassMethods(), tc, afterClassMethods);
fixMethodsWithClass(tc.getBeforeSuiteMethods(), tc, beforeSuiteMethods);
fixMethodsWithClass(tc.getAfterSuiteMethods(), tc, afterSuiteMethods);
fixMethodsWithClass(tc.getBeforeTestConfigurationMethods(), tc, beforeXmlTestMethods);
fixMethodsWithClass(tc.getAfterTestConfigurationMethods(), tc, afterXmlTestMethods);
fixMethodsWithClass(
tc.getBeforeGroupsMethods(),
tc,
MethodHelper.uniqueMethodList(beforeGroupMethods.values()));
fixMethodsWithClass(
tc.getAfterGroupsMethods(),
tc,
MethodHelper.uniqueMethodList(afterGroupMethods.values()));
}
//
// Sort the methods
//
m_beforeSuiteMethods =
MethodHelper.collectAndOrderMethods(
beforeSuiteMethods,
false /* forTests */,
m_runInfo,
m_annotationFinder,
true /* unique */,
m_excludedMethods,
comparator);
m_beforeXmlTestMethods =
MethodHelper.collectAndOrderMethods(
beforeXmlTestMethods,
false /* forTests */,
m_runInfo,
m_annotationFinder,
true /* unique (CQ added by me)*/,
m_excludedMethods,
comparator);
m_allTestMethods =
MethodHelper.collectAndOrderMethods(
testMethods,
true /* forTest? */,
m_runInfo,
m_annotationFinder,
false /* unique */,
m_excludedMethods,
comparator);
m_classMethodMap = new ClassMethodMap(Arrays.asList(m_allTestMethods), m_xmlMethodSelector);
m_afterXmlTestMethods =
MethodHelper.collectAndOrderMethods(
afterXmlTestMethods,
false /* forTests */,
m_runInfo,
m_annotationFinder,
true /* unique (CQ added by me)*/,
m_excludedMethods,
comparator);
m_afterSuiteMethods =
MethodHelper.collectAndOrderMethods(
afterSuiteMethods,
false /* forTests */,
m_runInfo,
m_annotationFinder,
true /* unique */,
m_excludedMethods,
comparator);
// shared group methods
m_groupMethods =
new ConfigurationGroupMethods(m_allTestMethods, beforeGroupMethods, afterGroupMethods);
}
public Collection getTestClasses() {
return m_classMap.values();
}
public void setTestName(String name) {
m_testName = name;
}
public void setOutputDirectory(String od) {
m_outputDirectory = od;
}
private void addMetaGroup(String name, List groupNames) {
m_metaGroups.put(name, groupNames);
}
private Map createGroups(List groups) {
return GroupsHelper.createGroups(m_metaGroups, groups);
}
/**
* The main entry method for TestRunner.
*
* This is where all the hard work is done: - Invoke configuration methods - Invoke test
* methods - Catch exceptions - Collect results - Invoke listeners - etc...
*/
public void run() {
beforeRun();
try {
XmlTest test = getTest();
if (test.isJUnit()) {
privateRunJUnit();
} else {
privateRun(test);
}
} finally {
afterRun();
}
}
/** Before run preparements. */
private void beforeRun() {
//
// Log the start date
//
m_startDate = new Date(System.currentTimeMillis());
// Log start
logStart();
// Invoke listeners
fireEvent(true /*start*/);
// invoke @BeforeTest
ITestNGMethod[] testConfigurationMethods = getBeforeTestConfigurationMethods();
invokeTestConfigurations(testConfigurationMethods);
}
private void invokeTestConfigurations(ITestNGMethod[] testConfigurationMethods) {
if (null != testConfigurationMethods && testConfigurationMethods.length > 0) {
ConfigMethodArguments arguments = new Builder()
.usingConfigMethodsAs(testConfigurationMethods)
.forSuite(m_xmlTest.getSuite())
.usingParameters(m_xmlTest.getAllParameters())
.build();
m_invoker.getConfigInvoker().invokeConfigurations(arguments);
}
}
private void privateRunJUnit() {
final ClassInfoMap cim = new ClassInfoMap(m_testClassesFromXml, false);
final Set> classes = cim.getClasses();
final List runMethods = Lists.newArrayList();
List> workers = Lists.newArrayList();
// FIXME: directly referencing JUnitTestRunner which uses JUnit classes
// may result in an class resolution exception under different JVMs
// The resolution process is not specified in the JVM spec with a specific implementation,
// so it can be eager => failure
workers.add(
new IWorker() {
/** @see TestMethodWorker#getTimeOut() */
@Override
public long getTimeOut() {
return 0;
}
/** @see java.lang.Runnable#run() */
@Override
public void run() {
for (Class tc : classes) {
List includedMethods = cim.getXmlClass(tc).getIncludedMethods();
List methods = Lists.newArrayList();
for (XmlInclude inc : includedMethods) {
methods.add(inc.getName());
}
IJUnitTestRunner tr = IJUnitTestRunner.createTestRunner(TestRunner.this);
tr.setInvokedMethodListeners(m_invokedMethodListeners);
try {
tr.run(tc, methods.toArray(new String[0]));
} catch (Exception ex) {
LOGGER.error(ex.getMessage(), ex);
} finally {
runMethods.addAll(tr.getTestMethods());
}
}
}
@Override
public List getTasks() {
throw new TestNGException("JUnit not supported");
}
@Override
public int getPriority() {
if (m_allTestMethods.length == 1) {
return m_allTestMethods[0].getPriority();
} else {
return 0;
}
}
@Override
public int compareTo(@Nonnull IWorker other) {
return getPriority() - other.getPriority();
}
});
runJUnitWorkers(workers);
m_allTestMethods = runMethods.toArray(new ITestNGMethod[0]);
}
private static Comparator newComparator(boolean needPrioritySort) {
return needPrioritySort ? new TestMethodComparator() : null;
}
private boolean sortOnPriority(ITestNGMethod[] interceptedOrder) {
return m_methodInterceptors.size() > 1 ||
Arrays.stream(interceptedOrder).anyMatch(m -> m.getPriority() != 0);
}
// If any of the test methods specify a priority other than the default, we'll need to be able to sort them.
private static BlockingQueue newQueue(boolean needPrioritySort) {
return needPrioritySort ? new PriorityBlockingQueue<>() : new LinkedBlockingQueue<>();
}
/**
* Main method that create a graph of methods and then pass it to the graph executor to run them.
*/
private void privateRun(XmlTest xmlTest) {
boolean parallel = xmlTest.getParallel().isParallel();
// parallel
int threadCount = parallel ? xmlTest.getThreadCount() : 1;
// Make sure we create a graph based on the intercepted methods, otherwise an interceptor
// removing methods would cause the graph never to terminate (because it would expect
// termination from methods that never get invoked).
ITestNGMethod[] interceptedOrder = intercept(m_allTestMethods);
IDynamicGraph graph =
DynamicGraphHelper.createDynamicGraph(interceptedOrder, getCurrentXmlTest());
graph.setVisualisers(this.visualisers);
// In some cases, additional sorting is needed to make sure tests run in the appropriate order.
// If the user specified a method interceptor, or if we have any methods that have a non-default
// priority on them, we need to sort.
boolean needPrioritySort = sortOnPriority(interceptedOrder);
Comparator methodComparator = newComparator(needPrioritySort);
if (parallel) {
if (graph.getNodeCount() <= 0) {
return;
}
ITestNGThreadPoolExecutor executor =
this.m_configuration.getExecutorFactory().newTestMethodExecutor(
"test=" + xmlTest.getName(),
graph,
this,
threadCount,
threadCount,
0,
TimeUnit.MILLISECONDS,
newQueue(needPrioritySort),
methodComparator);
executor.run();
try {
long timeOut = m_xmlTest.getTimeOut(XmlTest.DEFAULT_TIMEOUT_MS);
Utils.log(
"TestRunner",
2,
"Starting executor for test "
+ m_xmlTest.getName()
+ " with time out:"
+ timeOut
+ " milliseconds.");
executor.awaitTermination(timeOut, TimeUnit.MILLISECONDS);
executor.shutdownNow();
} catch (InterruptedException handled) {
LOGGER.error(handled.getMessage(), handled);
Thread.currentThread().interrupt();
}
return;
}
List freeNodes = graph.getFreeNodes();
if (graph.getNodeCount() > 0 && freeNodes.isEmpty()) {
throw new TestNGException("No free nodes found in:" + graph);
}
while (!freeNodes.isEmpty()) {
if (needPrioritySort) {
freeNodes.sort(methodComparator);
// Since this is sequential, let's run one at a time and fetch/sort freeNodes after each method.
// Future task: To optimize this, we can only update freeNodes after running a test that another test is dependent upon.
freeNodes = freeNodes.subList(0, 1);
}
createWorkers(freeNodes).forEach(Runnable::run);
graph.setStatus(freeNodes, IDynamicGraph.Status.FINISHED);
freeNodes = graph.getFreeNodes();
}
}
/** Apply the method interceptor (if applicable) to the list of methods. */
private ITestNGMethod[] intercept(ITestNGMethod[] methods) {
List methodInstances =
MethodHelper.methodsToMethodInstances(Arrays.asList(methods));
for (IMethodInterceptor m_methodInterceptor : m_methodInterceptors) {
methodInstances = m_methodInterceptor.intercept(methodInstances, this);
}
List result = MethodHelper.methodInstancesToMethods(methodInstances);
// Since an interceptor is involved, we would need to ensure that the ClassMethodMap object is
// in sync with the
// output of the interceptor, else @AfterClass doesn't get executed at all when interceptors are
// involved.
// so let's update the current classMethodMap object with the list of methods obtained from the
// interceptor.
this.m_classMethodMap = new ClassMethodMap(result, null);
ITestNGMethod[] resultArray = result.toArray(new ITestNGMethod[0]);
// Check if an interceptor had altered the effective test method count. If yes, then we need to
// update our configurationGroupMethod object with that information.
if (resultArray.length != m_groupMethods.getAllTestMethods().length) {
m_groupMethods =
new ConfigurationGroupMethods(
resultArray,
m_groupMethods.getBeforeGroupsMethods(),
m_groupMethods.getAfterGroupsMethods());
}
// If the user specified a method interceptor, whatever that returns is the order we're going
// to run things in. Set the intercepted priority for that case.
// There's a built-in interceptor, so look for more than one.
if (m_methodInterceptors.size() > 1) {
for (int i = 0; i < resultArray.length; ++i) {
resultArray[i].setInterceptedPriority(i);
}
}
return resultArray;
}
/**
* Create a list of workers to run the methods passed in parameter. Each test method is run in its
* own worker except in the following cases: - The method belongs to a class that
* has @Test(sequential=true) - The parallel attribute is set to "classes" In both these cases,
* all the methods belonging to that class will then be put in the same worker in order to run in
* the same thread.
*/
@Override
public List> createWorkers(List methods) {
AbstractParallelWorker.Arguments args =
new AbstractParallelWorker.Arguments.Builder()
.classMethodMap(this.m_classMethodMap)
.configMethods(this.m_groupMethods)
.finder(this.m_annotationFinder)
.invoker(this.m_invoker)
.methods(methods)
.testContext(this)
.listeners(this.m_classListeners.values())
.build();
return AbstractParallelWorker.newWorker(m_xmlTest.getParallel(), m_xmlTest.getGroupByInstances()).createWorkers(args);
}
//
// Invoke the workers
//
private void runJUnitWorkers(List> workers) {
// Sequential run
workers.forEach(Runnable::run);
}
private void afterRun() {
// invoke @AfterTest
ITestNGMethod[] testConfigurationMethods = getAfterTestConfigurationMethods();
invokeTestConfigurations(testConfigurationMethods);
//
// Log the end date
//
m_endDate = new Date(System.currentTimeMillis());
dumpInvokedMethods();
// Invoke listeners
fireEvent(false /*stop*/);
}
/** Logs the beginning of the {@link #beforeRun()} . */
private void logStart() {
log(
"Running test "
+ m_testName
+ " on "
+ m_classMap.size()
+ " "
+ " classes, "
+ " included groups:["
+ Strings.valueOf(m_xmlMethodSelector.getIncludedGroups())
+ "] excluded groups:["
+ Strings.valueOf(m_xmlMethodSelector.getExcludedGroups())
+ "]");
if (getVerbose() >= 3) {
for (ITestClass tc : m_classMap.values()) {
((TestClass) tc).dump();
}
}
}
/**
* Trigger the start/finish event.
*
* @param isStart true if the event is for start, false if the event is for
* finish
*/
private void fireEvent(boolean isStart) {
for (ITestListener itl : m_testListeners) {
if (isStart) {
itl.onStart(this);
} else {
itl.onFinish(this);
}
}
}
/////
// ITestContext
//
@Override
public String getName() {
return m_testName;
}
/** @return Returns the startDate. */
@Override
public Date getStartDate() {
return m_startDate;
}
/** @return Returns the endDate. */
@Override
public Date getEndDate() {
return m_endDate;
}
@Override
public IResultMap getPassedTests() {
return m_passedTests;
}
@Override
public IResultMap getSkippedTests() {
return m_skippedTests;
}
@Override
public IResultMap getFailedTests() {
return m_failedTests;
}
@Override
public IResultMap getFailedButWithinSuccessPercentageTests() {
return m_failedButWithinSuccessPercentageTests;
}
@Override
public String[] getIncludedGroups() {
Map ig = m_xmlMethodSelector.getIncludedGroups();
return ig.values().toArray(new String[0]);
}
@Override
public String[] getExcludedGroups() {
Map eg = m_xmlMethodSelector.getExcludedGroups();
return eg.values().toArray(new String[0]);
}
@Override
public String getOutputDirectory() {
return m_outputDirectory;
}
/** @return Returns the suite. */
@Override
public ISuite getSuite() {
return m_suite;
}
@Override
public ITestNGMethod[] getAllTestMethods() {
return m_allTestMethods;
}
@Override
public String getHost() {
return m_host;
}
@Override
public Collection getExcludedMethods() {
Map vResult = Maps.newHashMap();
for (ITestNGMethod m : m_excludedMethods) {
vResult.put(m, m);
}
return vResult.keySet();
}
/** @see org.testng.ITestContext#getFailedConfigurations() */
@Override
public IResultMap getFailedConfigurations() {
return m_failedConfigurations;
}
/** @see org.testng.ITestContext#getPassedConfigurations() */
@Override
public IResultMap getPassedConfigurations() {
return m_passedConfigurations;
}
/** @see org.testng.ITestContext#getSkippedConfigurations() */
@Override
public IResultMap getSkippedConfigurations() {
return m_skippedConfigurations;
}
@Override
public void addPassedTest(ITestNGMethod tm, ITestResult tr) {
m_passedTests.addResult(tr, tm);
}
@Override
public Set getPassedTests(ITestNGMethod tm) {
return m_passedTests.getResults(tm);
}
@Override
public Set getFailedTests(ITestNGMethod tm) {
return m_failedTests.getResults(tm);
}
@Override
public Set getSkippedTests(ITestNGMethod tm) {
return m_skippedTests.getResults(tm);
}
@Override
public void addSkippedTest(ITestNGMethod tm, ITestResult tr) {
m_skippedTests.addResult(tr, tm);
}
@Override
public void addInvokedMethod(InvokedMethod im) {
m_invokedMethods.add(im);
}
@Override
public void addFailedTest(ITestNGMethod testMethod, ITestResult result) {
logFailedTest(testMethod, result, false /* withinSuccessPercentage */);
}
@Override
public void addFailedButWithinSuccessPercentageTest(
ITestNGMethod testMethod, ITestResult result) {
logFailedTest(testMethod, result, true /* withinSuccessPercentage */);
}
@Override
public XmlTest getTest() {
return m_xmlTest;
}
@Override
public List getTestListeners() {
return m_testListeners;
}
@Override
public List getConfigurationListeners() {
List listeners = Lists.newArrayList(m_configurationListeners);
for (IConfigurationListener each : this.m_configuration.getConfigurationListeners()) {
boolean duplicate = false;
for (IConfigurationListener listener : listeners) {
if (each.getClass().equals(listener.getClass())) {
duplicate = true;
break;
}
}
if (!duplicate) {
listeners.add(each);
}
}
return Lists.newArrayList(listeners);
}
private void logFailedTest(
ITestNGMethod method, ITestResult tr, boolean withinSuccessPercentage) {
if (withinSuccessPercentage) {
m_failedButWithinSuccessPercentageTests.addResult(tr, method);
} else {
m_failedTests.addResult(tr, method);
}
}
private static void log(String s) {
Utils.log("TestRunner", 3, s);
}
public static int getVerbose() {
return m_verbose;
}
public void setVerbose(int n) {
m_verbose = n;
}
// TODO: This method needs to be removed and we need to be leveraging addListener().
// Investigate and fix this.
void addTestListener(ITestListener listener) {
if (!m_testListeners.contains(listener)) {
m_testListeners.add(listener);
}
}
public void addListener(ITestNGListener listener) {
// TODO a listener may be added many times if it implements many interfaces
if (listener instanceof IMethodInterceptor) {
m_methodInterceptors.add((IMethodInterceptor) listener);
}
if (listener instanceof ITestListener) {
// At this point, the field m_testListeners has already been used in the creation
addTestListener((ITestListener) listener);
}
if (listener instanceof IClassListener) {
IClassListener classListener = (IClassListener) listener;
if (!m_classListeners.containsKey(classListener.getClass())) {
m_classListeners.put(classListener.getClass(), classListener);
}
}
if (listener instanceof IConfigurationListener) {
addConfigurationListener((IConfigurationListener) listener);
}
if (listener instanceof IConfigurable) {
m_configuration.setConfigurable((IConfigurable) listener);
}
if (listener instanceof IHookable) {
m_configuration.setHookable((IHookable) listener);
}
if (listener instanceof IExecutionListener) {
IExecutionListener iel = (IExecutionListener) listener;
if (m_configuration.addExecutionListenerIfAbsent(iel)) {
iel.onExecutionStart();
}
}
if (listener instanceof IDataProviderListener) {
IDataProviderListener dataProviderListener = (IDataProviderListener) listener;
m_dataProviderListeners.put(dataProviderListener.getClass(), dataProviderListener);
}
if (listener instanceof IExecutionVisualiser) {
IExecutionVisualiser l = (IExecutionVisualiser) listener;
visualisers.add(l);
}
m_suite.addListener(listener);
}
void addConfigurationListener(IConfigurationListener icl) {
m_configurationListeners.add(icl);
}
private final Collection m_invokedMethods = new ConcurrentLinkedQueue<>();
private void dumpInvokedMethods() {
MethodHelper.dumpInvokedMethodsInfoToConsole(m_invokedMethods, getVerbose());
}
public List getInvokedMethods() {
return MethodHelper.invokedMethodsToMethods(m_invokedMethods);
}
private IResultMap m_passedConfigurations = new ResultMap();
private IResultMap m_skippedConfigurations = new ResultMap();
private IResultMap m_failedConfigurations = new ResultMap();
private class ConfigurationListener implements IConfigurationListener {
@Override
public void beforeConfiguration(ITestResult tr) {}
@Override
public void onConfigurationFailure(ITestResult itr) {
m_failedConfigurations.addResult(itr, itr.getMethod());
}
@Override
public void onConfigurationSkip(ITestResult itr) {
m_skippedConfigurations.addResult(itr, itr.getMethod());
}
@Override
public void onConfigurationSuccess(ITestResult itr) {
m_passedConfigurations.addResult(itr, itr.getMethod());
}
}
void addMethodInterceptor(IMethodInterceptor methodInterceptor) {
//avoid to add interceptor twice when the defined listeners implements both ITestListener and IMethodInterceptor.
if (!m_methodInterceptors.contains(methodInterceptor)) {
m_methodInterceptors.add(methodInterceptor);
}
}
@Override
public XmlTest getCurrentXmlTest() {
return m_xmlTest;
}
private IAttributes m_attributes = new Attributes();
@Override
public Object getAttribute(String name) {
return m_attributes.getAttribute(name);
}
@Override
public void setAttribute(String name, Object value) {
m_attributes.setAttribute(name, value);
}
@Override
public Set getAttributeNames() {
return m_attributes.getAttributeNames();
}
@Override
public Object removeAttribute(String name) {
return m_attributes.removeAttribute(name);
}
private ListMultiMap, Module> m_guiceModules = Maps.newListMultiMap();
@Override
public List getGuiceModules(Class cls) {
return m_guiceModules.get(cls);
}
private Map, Injector> m_injectors = Maps.newHashMap();
@Override
public Injector getInjector(List moduleInstances) {
return m_injectors.get(moduleInstances);
}
@Override
public Injector getInjector(IClass iClass) {
return guiceHelper.getInjector(iClass);
}
@Override
public void addInjector(List moduleInstances, Injector injector) {
m_injectors.put(moduleInstances, injector);
}
}