blob: d7081b316a29b4cfde30a75e59eabb03d57cac5a [file] [log] [blame]
package org.testng;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.testng.collections.ListMultiMap;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.internal.Attributes;
import org.testng.internal.ClassHelper;
import org.testng.internal.ClassInfoMap;
import org.testng.internal.ConfigurationGroupMethods;
import org.testng.internal.Constants;
import org.testng.internal.DynamicGraph;
import org.testng.internal.IConfiguration;
import org.testng.internal.IInvoker;
import org.testng.internal.ITestResultNotifier;
import org.testng.internal.InvokedMethod;
import org.testng.internal.Invoker;
import org.testng.internal.MethodGroupsHelper;
import org.testng.internal.MethodHelper;
import org.testng.internal.MethodInstance;
import org.testng.internal.ResultMap;
import org.testng.internal.RunInfo;
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.internal.annotations.IListeners;
import org.testng.internal.annotations.Sets;
import org.testng.internal.thread.ThreadUtil;
import org.testng.internal.thread.graph.GraphThreadPoolExecutor;
import org.testng.internal.thread.graph.IThreadWorkerFactory;
import org.testng.internal.thread.graph.IWorker;
import org.testng.junit.IJUnitTestRunner;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlPackage;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;
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.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
/**
* This class takes care of running one Test.
*
* @author Cedric Beust, Apr 26, 2004
*/
public class TestRunner
implements ITestContext, ITestResultNotifier, IThreadWorkerFactory<ITestNGMethod>
{
/* generated */
private static final long serialVersionUID = 4247820024988306670L;
private ISuite m_suite;
private XmlTest m_xmlTest;
private String m_testName;
transient private List<XmlClass> m_testClassesFromXml= null;
transient private List<XmlPackage> m_packageNamesFromXml= null;
transient private IInvoker m_invoker= null;
transient private IAnnotationFinder m_annotationFinder= null;
/** ITestListeners support. */
transient private List<ITestListener> m_testListeners = Lists.newArrayList();
transient private List<IConfigurationListener> m_configurationListeners = Lists.newArrayList();
transient private IConfigurationListener m_confListener= new ConfigurationListener();
transient private boolean m_skipFailedInvocationCounts;
/**
* 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 = null;
private Date m_endDate = null;
/** A map to keep track of Class <-> IClass. */
transient private Map<Class<?>, ITestClass> m_classMap = Maps.newHashMap();
/** Where the reports will be created. */
private String m_outputDirectory= Constants.getDefaultValueFor(Constants.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<ITestNGMethod> m_excludedMethods = Lists.newArrayList();
private ConfigurationGroupMethods m_groupMethods = null;
// Meta groups
private Map<String, List<String>> 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 <test preserve-order="true/false">
private transient IMethodInterceptor m_methodInterceptor;
private transient ClassMethodMap m_classMethodMap;
private transient TestNGClassFinder m_testClassFinder;
private transient IConfiguration m_configuration;
protected TestRunner(IConfiguration configuration,
ISuite suite,
XmlTest test,
String outputDirectory,
IAnnotationFinder finder,
boolean skipFailedInvocationCounts,
List<IInvokedMethodListener> invokedMethodListeners)
{
init(configuration, suite, test, outputDirectory, finder, skipFailedInvocationCounts,
invokedMethodListeners);
}
public TestRunner(IConfiguration configuration, ISuite suite, XmlTest test,
boolean skipFailedInvocationCounts,
List<IInvokedMethodListener> listeners) {
init(configuration, suite, test, suite.getOutputDirectory(),
suite.getAnnotationFinder(test.getAnnotations()),
skipFailedInvocationCounts, listeners);
}
private void init(IConfiguration configuration,
ISuite suite,
XmlTest test,
String outputDirectory,
IAnnotationFinder annotationFinder,
boolean skipFailedInvocationCounts,
List<IInvokedMethodListener> invokedMethodListeners)
{
m_configuration = configuration;
m_xmlTest= test;
m_suite = suite;
m_testName = test.getName();
m_host = suite.getHost();
m_testClassesFromXml= test.getXmlClasses();
m_skipFailedInvocationCounts = skipFailedInvocationCounts;
setVerbose(test.getVerbose());
boolean preserveOrder = "true".equalsIgnoreCase(test.getPreserveOrder());
m_methodInterceptor = preserveOrder ? new PreserveOrderMethodInterceptor()
: new InstanceOrderingMethodInterceptor();
m_packageNamesFromXml= test.getXmlPackages();
if(null != m_packageNamesFromXml) {
for(XmlPackage xp: m_packageNamesFromXml) {
m_testClassesFromXml.addAll(xp.getXmlClasses());
}
}
m_annotationFinder= annotationFinder;
m_invoker = new Invoker(m_configuration, this, this, m_suite.getSuiteState(),
m_skipFailedInvocationCounts, invokedMethodListeners);
if (suite.getParallel() != null) {
log(3, "Running the tests in '" + test.getName() + "' with parallel mode:" + suite.getParallel());
}
setOutputDirectory(outputDirectory);
// Finish our initialization
init();
}
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);
}
private class ListenerHolder {
private List<Class<? extends ITestNGListener>> listenerClasses;
private Class<? extends ITestNGListenerFactory> listenerFactoryClass;
}
/**
* @return all the @Listeners annotations found in the current class and its
* superclasses.
*/
private ListenerHolder findAllListeners(Class<?> cls) {
ListenerHolder result = new ListenerHolder();
result.listenerClasses = Lists.newArrayList();
do {
IListeners l = (IListeners) m_annotationFinder.findAnnotation(cls, IListeners.class);
if (l != null) {
Class<? extends ITestNGListener>[] classes = l.getValue();
for (Class<? extends ITestNGListener> c : classes) {
result.listenerClasses.add(c);
if (ITestNGListenerFactory.class.isAssignableFrom(c)) {
if (result.listenerFactoryClass == null) {
result.listenerFactoryClass = (Class<? extends ITestNGListenerFactory>) c;
}
else {
throw new TestNGException("Found more than one class implementing" +
"ITestNGListenerFactory:" + c + " and " + result.listenerFactoryClass);
}
}
}
}
cls = cls.getSuperclass();
} while (cls != Object.class);
return result;
}
private void initListeners() {
//
// Find all the listener factories and collect all the listeners requested in a
// @Listeners annotation.
//
Set<Class<? extends ITestNGListener>> listenerClasses = Sets.newHashSet();
Class<? extends ITestNGListenerFactory> listenerFactoryClass = null;
for (IClass cls : getTestClasses()) {
Class<? extends ITestNGListenerFactory> realClass = cls.getRealClass();
ListenerHolder listenerHolder = findAllListeners(realClass);
if (listenerFactoryClass == null) {
listenerFactoryClass = listenerHolder.listenerFactoryClass;
}
listenerClasses.addAll(listenerHolder.listenerClasses);
}
//
// 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 listenerFactory = null;
// If we found a test listener factory, instantiate it.
try {
if (m_testClassFinder != null) {
IClass ic = m_testClassFinder.getIClass(listenerFactoryClass);
if (ic != null) {
listenerFactory = (ITestNGListenerFactory) ic.getInstances(false)[0];
}
}
if (listenerFactory == null) {
listenerFactory = listenerFactoryClass != null ? listenerFactoryClass.newInstance() : null;
}
}
catch(Exception ex) {
throw new TestNGException("Couldn't instantiate the ITestNGListenerFactory: "
+ ex);
}
// Instantiate all the listeners
for (Class<? extends ITestNGListener> c : listenerClasses) {
Object listener = listenerFactory != null ? listenerFactory.createListener(c) : null;
if (listener == null) {
listener = ClassHelper.newInstance(c);
}
if (listener instanceof IMethodInterceptor) {
setMethodInterceptor((IMethodInterceptor) listener);
}
if (listener instanceof ISuiteListener) {
m_suite.addListener((ISuiteListener) listener);
}
if (listener instanceof IInvokedMethodListener) {
m_suite.addListener((ITestNGListener) 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 IConfigurationListener) {
addConfigurationListener((IConfigurationListener) listener);
}
if (listener instanceof IReporter) {
m_suite.addListener((ITestNGListener) 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;
iel.onExecutionStart();
m_configuration.addExecutionListener(iel);
}
}
}
/**
* Initialize meta groups
*/
private void initMetaGroups(XmlTest xmlTest) {
Map<String, List<String>> metaGroups = xmlTest.getMetaGroups();
for (Map.Entry<String, List<String>> 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.setExpression(m_xmlTest.getExpression());
// 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 = ClassHelper.createSelector(selector);
m_runInfo.addMethodSelector(s, selector.getPriority());
}
}
}
}
private void initMethods() {
//
// Calculate all the methods we need to invoke
//
List<ITestNGMethod> beforeClassMethods = Lists.newArrayList();
List<ITestNGMethod> testMethods = Lists.newArrayList();
List<ITestNGMethod> afterClassMethods = Lists.newArrayList();
List<ITestNGMethod> beforeSuiteMethods = Lists.newArrayList();
List<ITestNGMethod> afterSuiteMethods = Lists.newArrayList();
List<ITestNGMethod> beforeXmlTestMethods = Lists.newArrayList();
List<ITestNGMethod> afterXmlTestMethods = Lists.newArrayList();
ClassInfoMap classMap = new ClassInfoMap(m_testClassesFromXml);
m_testClassFinder= new TestNGClassFinder(classMap,
null,
m_xmlTest,
m_configuration,
this);
ITestMethodFinder testMethodFinder
= new TestNGMethodFinder<ITestNGMethod>(m_runInfo, m_annotationFinder);
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_runInfo,
m_xmlTest,
classMap.getXmlClass(ic.getRealClass()));
m_classMap.put(ic.getRealClass(), tc);
}
//
// Calculate groups methods
//
Map<String, List<ITestNGMethod>> beforeGroupMethods= MethodGroupsHelper.findGroupsMethods(m_classMap.values(), true);
Map<String, List<ITestNGMethod>> 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);
m_beforeXmlTestMethods = MethodHelper.collectAndOrderMethods(beforeXmlTestMethods,
false /* forTests */,
m_runInfo,
m_annotationFinder,
true /* unique (CQ added by me)*/,
m_excludedMethods);
m_allTestMethods = MethodHelper.collectAndOrderMethods(testMethods,
true /* forTest? */,
m_runInfo,
m_annotationFinder,
false /* unique */,
m_excludedMethods);
m_classMethodMap = new ClassMethodMap(m_allTestMethods);
m_afterXmlTestMethods = MethodHelper.collectAndOrderMethods(afterXmlTestMethods,
false /* forTests */,
m_runInfo,
m_annotationFinder,
true /* unique (CQ added by me)*/,
m_excludedMethods);
m_afterSuiteMethods = MethodHelper.collectAndOrderMethods(afterSuiteMethods,
false /* forTests */,
m_runInfo,
m_annotationFinder,
true /* unique */,
m_excludedMethods);
// shared group methods
m_groupMethods = new ConfigurationGroupMethods(m_allTestMethods, beforeGroupMethods, afterGroupMethods);
}
private void fixMethodsWithClass(ITestNGMethod[] methods,
ITestClass testCls,
List<ITestNGMethod> methodList) {
for (ITestNGMethod itm : methods) {
itm.setTestClass(testCls);
if (methodList != null) {
methodList.add(itm);
}
}
}
public Collection<ITestClass> getTestClasses() {
return m_classMap.values();
}
public void setTestName(String name) {
m_testName = name;
}
public void setOutputDirectory(String od) {
m_outputDirectory= od;
// FIX: empty directories were created
// if (od == null) { m_outputDirectory = null; return; } //for maven2
// File file = new File(od);
// file.mkdirs();
// m_outputDirectory= file.getAbsolutePath();
}
private void addMetaGroup(String name, List<String> groupNames) {
m_metaGroups.put(name, groupNames);
}
/**
* Calculate the transitive closure of all the MetaGroups
*
* @param groups
* @param unfinishedGroups
* @param result The transitive closure containing all the groups found
*/
private void collectGroups(String[] groups,
List<String> unfinishedGroups,
Map<String, String> result) {
for (String gn : groups) {
List<String> subGroups = m_metaGroups.get(gn);
if (null != subGroups) {
for (String sg : subGroups) {
if (null == result.get(sg)) {
result.put(sg, sg);
unfinishedGroups.add(sg);
}
}
}
}
}
private Map<String, String> createGroups(List<String> groups) {
return createGroups(groups.toArray(new String[groups.size()]));
}
private Map<String, String> createGroups(String[] groups) {
Map<String, String> result = Maps.newHashMap();
// Groups that were passed on the command line
for (String group : groups) {
result.put(group, group);
}
// See if we have any MetaGroups and
// expand them if they match one of the groups
// we have just been passed
List<String> unfinishedGroups = Lists.newArrayList();
if (m_metaGroups.size() > 0) {
collectGroups(groups, unfinishedGroups, result);
// Do we need to loop over unfinished groups?
while (unfinishedGroups.size() > 0) {
String[] uGroups = unfinishedGroups.toArray(new String[unfinishedGroups.size()]);
unfinishedGroups = Lists.newArrayList();
collectGroups(uGroups, unfinishedGroups, result);
}
}
// Utils.dumpMap(result);
return result;
}
/**
* 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(test);
}
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();
if(null != testConfigurationMethods && testConfigurationMethods.length > 0) {
m_invoker.invokeConfigurations(null,
testConfigurationMethods,
m_xmlTest.getSuite(),
m_xmlTest.getParameters(),
null, /* no parameter values */
null /* instance */);
}
}
private void privateRunJUnit(XmlTest xmlTest) {
ClassInfoMap cim = new ClassInfoMap(m_testClassesFromXml);
final Set<Class<?>> classes = cim.getClasses();
final List<ITestNGMethod> runMethods = Lists.newArrayList();
List<IWorker<ITestNGMethod>> 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<ITestNGMethod>() {
/**
* @see org.testng.internal.IMethodWorker#getMaxTimeOut()
*/
@Override
public long getTimeOut() {
return 0;
}
/**
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
for(Class<?> tc: classes) {
IJUnitTestRunner tr= ClassHelper.createTestRunner(TestRunner.this);
try {
tr.run(tc);
}
catch(Exception ex) {
ex.printStackTrace();
}
finally {
runMethods.addAll(tr.getTestMethods());
}
}
}
@Override
public List<ITestNGMethod> 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(IWorker<ITestNGMethod> other) {
return getPriority() - other.getPriority();
}
});
runWorkers(workers, "" /* JUnit does not support parallel */, null);
m_allTestMethods= runMethods.toArray(new ITestNGMethod[runMethods.size()]);
}
private void privateRun(XmlTest xmlTest) {
//
// Calculate the lists of tests that can be run in sequence and in parallel
//
List<List<ITestNGMethod>> sequentialList= Lists.newArrayList();
List<ITestNGMethod> parallelList= Lists.newArrayList();
ListMultiMap<Integer, ITestNGMethod> sequentialMapList = Maps.newListMultiMap();
String parallelMode = xmlTest.getParallel();
boolean parallel = XmlSuite.PARALLEL_METHODS.equals(parallelMode)
|| "true".equalsIgnoreCase(parallelMode)
|| XmlSuite.PARALLEL_CLASSES.equals(parallelMode);
if (!parallel) {
// sequential
computeTestLists(sequentialList, parallelList, sequentialMapList);
int seqCount = 0;
for (List<ITestNGMethod> l : sequentialList) {
seqCount += l.size();
}
log(3, "Found " + seqCount + " sequential methods and " + parallelList.size()
+ " parallel methods");
//
// If the user specified preserve-order = true, we can't change the ordering
// of the methods on the sequential list, since they are not free, however
// we can still reorder the classes to reflect that order.
//
if ("true".equalsIgnoreCase(xmlTest.getPreserveOrder())) {
// Note: modifying sequentialList
sequentialList = preserveClassOrder(xmlTest, sequentialList);
}
//
// Create the workers
//
List<TestMethodWorker> workers = Lists.newArrayList();
createSequentialWorkers(sequentialList, xmlTest, m_classMethodMap, workers);
ListMultiMap<Integer, TestMethodWorker> ml =
createSequentialWorkers(sequentialMapList, xmlTest.getParameters(), m_classMethodMap);
// All the parallel tests are placed in a separate worker, so they can be
// invoked in parallel
createParallelWorkers(parallelList, xmlTest, m_classMethodMap, workers);
// m_testPlan =
// new TestPlan(sequentialList, parallelList, cmm,
// getBeforeSuiteMethods(), getAfterSuiteMethods(),
// m_groupMethods, xmlTest);
try {
// Sort by priorities
Collections.sort(workers);
runWorkers(workers, xmlTest.getParallel(), ml);
}
finally {
m_classMethodMap.clear();
}
}
else {
// parallel
int threadCount = xmlTest.getThreadCount();
// 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).
DynamicGraph<ITestNGMethod> graph = computeAlternateTestList(intercept(m_allTestMethods));
if (graph.getNodeCount() > 0) {
GraphThreadPoolExecutor<ITestNGMethod> executor =
new GraphThreadPoolExecutor<ITestNGMethod>(graph, this,
threadCount, threadCount, 0, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
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 e) {
e.printStackTrace();
}
}
}
}
/**
* Apply the method interceptor (if applicable) to the list of methods.
*/
private ITestNGMethod[] intercept(ITestNGMethod[] methods) {
if (m_methodInterceptor == null) return methods;
IMethodInstance[] instances = methodsToMethodInstances(Arrays.asList(methods));
List<IMethodInstance> resultInstances =
m_methodInterceptor.intercept(Arrays.asList(instances), this);
List<ITestNGMethod> result = Lists.newArrayList();
for (IMethodInstance imi : resultInstances) {
result.add(imi.getMethod());
}
return result.toArray(new ITestNGMethod[result.size()]);
}
/**
* Reorder the methods to preserve the class order without changing the method ordering.
*/
private List<List<ITestNGMethod>> preserveClassOrder(XmlTest test,
List<List<ITestNGMethod>> lists) {
List<List<ITestNGMethod>> result = Lists.newArrayList();
Map<String, List<ITestNGMethod>> classes = Maps.newHashMap();
List<XmlClass> sortedClasses = Lists.newArrayList();
for (XmlClass c : test.getXmlClasses()) {
classes.put(c.getName(), new ArrayList<ITestNGMethod>());
sortedClasses.add(c);
}
// Sort the classes based on their order of appearance in the XML
Collections.sort(sortedClasses, new Comparator<XmlClass>() {
@Override
public int compare(XmlClass arg0, XmlClass arg1) {
return arg0.getIndex() - arg1.getIndex();
}
});
// Put each method in their class bucket
for (List<ITestNGMethod> ll : lists) {
for (ITestNGMethod m : ll) {
String declaredClass = m.getTestClass().getName();
List<ITestNGMethod> l = classes.get(declaredClass);
// The list might be null if the class came from somewhere else than XML,
// e.g. a factory
if (l == null) {
l = Lists.newArrayList();
classes.put(declaredClass, l);
}
l.add(m);
}
}
// Recreate the list based on the class ordering
List<ITestNGMethod> tmpResult = Lists.newArrayList();
for (XmlClass xc : sortedClasses) {
List<ITestNGMethod> methods = classes.get(xc.getName());
tmpResult.addAll(methods);
}
result.add(tmpResult);
// }
// System.out.println(result);
return result;
}
/**
* 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<IWorker<ITestNGMethod>> createWorkers(Set<ITestNGMethod> methods) {
List<IWorker<ITestNGMethod>> result = Lists.newArrayList();
// Methods that belong to classes with a sequential=true or parallel=classes
// attribute must all be run in the same worker
Set<Class> sequentialClasses = Sets.newHashSet();
for (ITestNGMethod m : methods) {
Class<? extends ITestClass> cls = m.getRealClass();
org.testng.annotations.ITestAnnotation test =
(org.testng.annotations.ITestAnnotation) m_annotationFinder.
findAnnotation(cls,
org.testng.annotations.ITestAnnotation.class);
// If either sequential=true or parallel=classes, mark this class sequential
if (test != null && (test.getSequential() || test.getSingleThreaded()) ||
XmlSuite.PARALLEL_CLASSES.equals(m_xmlTest.getParallel())) {
sequentialClasses.add(cls);
}
}
List<IMethodInstance> methodInstances = Lists.newArrayList();
for (ITestNGMethod tm : methods) {
methodInstances.addAll(methodsToMultipleMethodInstances(tm));
}
//
// Finally, sort the parallel methods by classes
//
methodInstances = m_methodInterceptor.intercept(methodInstances, this);
Map<String, String> params = m_xmlTest.getParameters();
Set<Class<?>> processedClasses = Sets.newHashSet();
for (IMethodInstance im : methodInstances) {
Class<?> c = im.getMethod().getTestClass().getRealClass();
if (sequentialClasses.contains(c)) {
if (!processedClasses.contains(c)) {
processedClasses.add(c);
if (System.getProperty("experimental") != null) {
List<IMethodInstance>[] instances = createInstances(methodInstances);
for (List<IMethodInstance> inst : instances) {
TestMethodWorker worker = createTestMethodWorker(inst, params, c);
result.add(worker);
}
}
else {
// Sequential class: all methods in one worker
TestMethodWorker worker = createTestMethodWorker(methodInstances, params, c);
result.add(worker);
}
}
}
else {
// Parallel class: each method in its own worker
TestMethodWorker worker = createTestMethodWorker(Arrays.asList(im), params, c);
result.add(worker);
}
}
// Sort by priorities
Collections.sort(result);
return result;
}
private List<IMethodInstance>[] createInstances(List<IMethodInstance> methodInstances) {
Map<Object, List<IMethodInstance>> map = Maps.newHashMap();
// MapList<IMethodInstance[], Object> map = new MapList<IMethodInstance[], Object>();
for (IMethodInstance imi : methodInstances) {
for (Object o : imi.getInstances()) {
System.out.println(o);
List<IMethodInstance> l = map.get(o);
if (l == null) {
l = Lists.newArrayList();
map.put(o, l);
}
l.add(imi);
}
// for (Object instance : imi.getInstances()) {
// map.put(imi, instance);
// }
}
// return map.getKeys();
System.out.println(map);
List[] result = new List[map.size()];
int i = 0;
for (List<IMethodInstance> imi : map.values()) {
result[i++] = imi;
}
return result;
}
private TestMethodWorker createTestMethodWorker(
List<IMethodInstance> methodInstances, Map<String, String> params,
Class<?> c) {
return new TestMethodWorker(m_invoker,
findClasses(methodInstances, c),
m_xmlTest.getSuite(),
params,
m_allTestMethods,
m_groupMethods,
m_classMethodMap,
this);
}
private IMethodInstance[] findClasses(List<IMethodInstance> methodInstances, Class<?> c) {
List<IMethodInstance> result = Lists.newArrayList();
for (IMethodInstance mi : methodInstances) {
if (mi.getMethod().getTestClass().getRealClass() == c) {
result.add(mi);
}
}
return result.toArray(new IMethodInstance[result.size()]);
}
private void createParallelWorkers(List<ITestNGMethod> parallel,
XmlTest xmlTest, ClassMethodMap cmm, List<TestMethodWorker> workers) {
if(parallel.isEmpty()) {
return;
}
List<IMethodInstance> methodInstances = Lists.newArrayList();
for (ITestNGMethod tm : parallel) {
methodInstances.addAll(methodsToMultipleMethodInstances(tm));
}
//
// Finally, sort the parallel methods by classes
//
methodInstances = m_methodInterceptor.intercept(methodInstances, this);
if (getVerbose() >= 2) {
log(3, "Will be run in random order:");
for (IMethodInstance mi : methodInstances) {
log(3, " " + mi.getMethod());
log(3, " on instances");
for(Object o: mi.getInstances()) {
log(3, " " + o);
}
}
log(3, "===");
}
Map<String, String> params = xmlTest.getParameters();
for (IMethodInstance mi : methodInstances) {
workers.add(new TestMethodWorker(m_invoker,
new IMethodInstance[] { mi },
m_xmlTest.getSuite(),
params,
m_allTestMethods,
m_groupMethods,
cmm,
this));
}
}
/**
* @return a Set of arrays of IMethodInstances. Each element in the array is a method that belongs
* to the same class.
*/
private Map<Class, Set<IMethodInstance>> groupMethodInstancesByClass(List<IMethodInstance> instances) {
Map<Class, Set<IMethodInstance>> result = Maps.newHashMap();
for (IMethodInstance mi : instances) {
Class cl = mi.getMethod().getTestClass().getRealClass();
Set<IMethodInstance> methods = result.get(cl);
if (methods == null) {
methods = new HashSet<IMethodInstance>();
result.put(cl, methods);
}
methods.add(mi);
}
return result;
}
private void createSequentialWorkers(List<List<ITestNGMethod>> sequentialList,
XmlTest xmlTest, ClassMethodMap cmm, List<TestMethodWorker> workers) {
Map<String, String> params = xmlTest.getParameters();
if(sequentialList.isEmpty()) {
return;
}
Map<Object, List<ITestNGMethod>> map = Maps.newHashMap();
for (List<ITestNGMethod> sl : sequentialList) {
for (ITestNGMethod m : sl) {
for (Object o : m.getInstances()) {
List<ITestNGMethod> l = map.get(o);
if (l == null) {
l = Lists.newArrayList();
map.put(o, l);
}
l.add(m);
}
}
}
if (xmlTest.groupByInstances()) {
for (Map.Entry<Object, List<ITestNGMethod>> es : map.entrySet()) {
List<MethodInstance> instances = Lists.newArrayList();
for (ITestNGMethod m : es.getValue()) {
instances.add(new MethodInstance(m, new Object[] { es.getKey() }));
}
workers.add(new TestMethodWorker(m_invoker,
instances.toArray(new MethodInstance[instances.size()]),
m_xmlTest.getSuite(),
params,
m_allTestMethods,
m_groupMethods,
cmm,
this));
}
} else {
// All the sequential tests are place in one worker, guaranteeing they
// will be invoked sequentially
for (List<ITestNGMethod> sl : sequentialList) {
workers.add(new TestMethodWorker(m_invoker,
methodsToMethodInstances(sl),
m_xmlTest.getSuite(),
params,
m_allTestMethods,
m_groupMethods,
cmm,
this));
}
}
if (getVerbose() >= 2) {
log(3, "Will be run sequentially:");
for (List<ITestNGMethod> l : sequentialList) {
for (ITestNGMethod tm : l) {
log(3, " " + tm);
}
log(3, "====");
}
log(3, "===");
}
}
private ListMultiMap<Integer, TestMethodWorker> createSequentialWorkers(ListMultiMap<Integer,
ITestNGMethod> mapList, Map<String, String> params, ClassMethodMap cmm) {
ListMultiMap<Integer, TestMethodWorker> result = Maps.newListMultiMap();
// All the sequential tests are place in one worker, guaranteeing they
// will be invoked sequentially
for (Integer i : mapList.getKeys()) {
result.put(i,
new TestMethodWorker(m_invoker, methodsToMethodInstances(mapList.get(i)),
m_xmlTest.getSuite(), params, m_allTestMethods, m_groupMethods, cmm, this));
}
if (getVerbose() >= 2) {
log(3, "Will be run sequentially:" + result);
}
return result;
}
private List<MethodInstance> methodsToMultipleMethodInstances(ITestNGMethod... sl) {
List<MethodInstance> vResult = Lists.newArrayList();
for (ITestNGMethod m : sl) {
Object[] instances = m.getTestClass().getInstances(true);
for (Object instance : instances) {
vResult.add(new MethodInstance(m, new Object[] { instance }));
}
}
return vResult;
}
private MethodInstance[] methodsToMethodInstances(List<ITestNGMethod> sl) {
MethodInstance[] result = new MethodInstance[sl.size()];
for (int i = 0; i < result.length; i++) {
result[i] = new MethodInstance(sl.get(i), sl.get(i).getTestClass().getInstances(true));
}
return result;
}
//
// Invoke the workers
//
private void runWorkers(List<? extends IWorker<ITestNGMethod>> workers, String parallelMode,
ListMultiMap<Integer, TestMethodWorker> sequentialWorkers) {
if (XmlSuite.PARALLEL_METHODS.equals(parallelMode)
|| "true".equalsIgnoreCase(parallelMode)
|| XmlSuite.PARALLEL_CLASSES.equals(parallelMode))
{
//
// Parallel run
//
// Default timeout for individual methods: same as the test global-time-out, but
// overridden if a method defines its own.
long maxTimeOut = m_xmlTest.getTimeOut(XmlTest.DEFAULT_TIMEOUT_MS);
for (IWorker<ITestNGMethod> tmw : workers) {
long mt = tmw.getTimeOut();
if (mt > maxTimeOut) {
maxTimeOut= mt;
}
}
ThreadUtil.execute(workers, m_xmlTest.getThreadCount(), maxTimeOut, false);
// ThreadUtil.execute(sequentialWorkers);
}
else {
//
// Sequential run
//
for (IWorker<ITestNGMethod> tmw : workers) {
tmw.run();
}
}
}
private void afterRun() {
// invoke @AfterTest
ITestNGMethod[] testConfigurationMethods= getAfterTestConfigurationMethods();
if(null != testConfigurationMethods && testConfigurationMethods.length > 0) {
m_invoker.invokeConfigurations(null,
testConfigurationMethods,
m_xmlTest.getSuite(),
m_xmlTest.getParameters(),
null, /* no parameter values */
null /* instance */);
}
//
// Log the end date
//
m_endDate = new Date(System.currentTimeMillis());
if (getVerbose() >= 3) {
dumpInvokedMethods();
}
// Invoke listeners
fireEvent(false /*stop*/);
// Statistics
// logResults();
}
/**
* @param regexps
* @param group
* @return true if the map contains at least one regexp that matches the
* given group
*/
private boolean containsString(Map<String, String> regexps, String group) {
for (String regexp : regexps.values()) {
boolean match = Pattern.matches(regexp, group);
if (match) {
return true;
}
}
return false;
}
private DynamicGraph<ITestNGMethod> computeAlternateTestList(ITestNGMethod[] methods) {
DynamicGraph<ITestNGMethod> result = new DynamicGraph<ITestNGMethod>();
Map<String, ITestNGMethod> map = Maps.newHashMap();
ListMultiMap<String, ITestNGMethod> groups = Maps.newListMultiMap();
for (ITestNGMethod m : methods) {
map.put(m.getTestClass().getName() + "." + m.getMethodName(), m);
for (String g : m.getGroups()) {
groups.put(g, m);
}
}
// A map of each priority and the list of methods that have this priority
ListMultiMap<Integer, ITestNGMethod> methodsByPriority = Maps.newListMultiMap();
for (ITestNGMethod m : methods) {
methodsByPriority.put(m.getPriority(), m);
}
// The priority map will contain at least one entry for all the methods that have
// a priority of zero (the default). If it has more than one entry, then we know that
// some test methods specified priorities, so we need to create dependencies
// that reflect the priority order.
boolean hasPriorities = methodsByPriority.getSize() > 1;
for (ITestNGMethod m : methods) {
result.addNode(m);
// Priority
if (hasPriorities) {
for (Map.Entry<Integer, List<ITestNGMethod>> e : methodsByPriority.getEntrySet()) {
if (e.getKey() < m.getPriority()) {
for (ITestNGMethod dm : e.getValue()) {
result.addEdge(m, dm);
}
}
}
}
// Dependent methods
{
String[] dependentMethods = m.getMethodsDependedUpon();
if (dependentMethods != null) {
for (String d : dependentMethods) {
ITestNGMethod dm = map.get(d);
if (dm == null) {
throw new TestNGException("Method \"" + m
+ "\" depends on nonexistent method \"" + d + "\"");
}
result.addEdge(m, dm);
}
}
}
// Dependent groups
{
String[] dependentGroups = m.getGroupsDependedUpon();
for (String d : dependentGroups) {
List<ITestNGMethod> dg = groups.get(d);
if (dg == null) {
throw new TestNGException("Method \"" + m
+ "\" depends on nonexistent group \"" + d + "\"");
}
for (ITestNGMethod ddm : dg) {
result.addEdge(m, ddm);
}
}
}
}
return result;
}
/**
* Creates the
* @param sl the sequential list of methods
* @param parallelList the list of methods that can be run in parallel
*/
private void computeTestLists(List<List<ITestNGMethod>> sl,
List<ITestNGMethod> parallelList, ListMultiMap<Integer, ITestNGMethod> outSequentialList) {
Map<String, String> groupsDependedUpon = Maps.newHashMap();
Map<String, String> methodsDependedUpon = Maps.newHashMap();
Map<String, List<ITestNGMethod>> sequentialAttributeList = Maps.newHashMap();
List<ITestNGMethod> sequentialList = Lists.newArrayList();
for (int i= m_allTestMethods.length - 1; i >= 0; i--) {
ITestNGMethod tm= m_allTestMethods[i];
//
// If the class this method belongs to has @Test(sequential = true), we
// put this method in the sequential list right away
//
Class<?> cls= tm.getRealClass();
org.testng.annotations.ITestAnnotation test =
(org.testng.annotations.ITestAnnotation) m_annotationFinder.
findAnnotation(cls, org.testng.annotations.ITestAnnotation.class);
if (test != null) {
if (test.getSequential() || test.getSingleThreaded()) {
String className = tm.getTestClass().getName();
List<ITestNGMethod> list = sequentialAttributeList.get(className);
if (list == null) {
list = Lists.newArrayList();
sequentialAttributeList.put(className, list);
}
list.add(0, tm);
continue;
}
}
//
// Otherwise, determine if it depends on other methods/groups or if
// it is depended upon
//
String[] currentGroups = tm.getGroups();
String[] currentGroupsDependedUpon= tm.getGroupsDependedUpon();
String[] currentMethodsDependedUpon= tm.getMethodsDependedUpon();
String thisMethodName = tm.getMethod().getDeclaringClass().getName()
+ "." + tm.getMethod().getName();
if (currentGroupsDependedUpon.length > 0) {
for (String gdu : currentGroupsDependedUpon) {
groupsDependedUpon.put(gdu, gdu);
}
sequentialList.add(0, tm);
}
else if (currentMethodsDependedUpon.length > 0) {
for (String cmu : currentMethodsDependedUpon) {
methodsDependedUpon.put(cmu, cmu);
}
sequentialList.add(0, tm);
}
// Is there a method that depends on the current method?
else if (containsString(methodsDependedUpon, thisMethodName)) {
int index = 0;
for (int j = 0; j < sequentialList.size(); j++) {
ITestNGMethod m = sequentialList.get(j);
if (arrayContains(m.getMethodsDependedUpon(), thisMethodName)) {
index = j;
break;
}
}
// Insert the dependee as close to its dependent as possible (TESTNG-317)
sequentialList.add(index, tm);
}
else if (currentGroups.length > 0) {
boolean isSequential= false;
for (String group : currentGroups) {
if (containsString(groupsDependedUpon, group)) {
sequentialList.add(0, tm);
isSequential = true;
break;
}
}
if (!isSequential) {
parallelList.add(0, tm);
}
}
else {
parallelList.add(0, tm);
}
}
//
// Put all the sequential methods in the output argument
//
if(sequentialList.size() > 0) {
sl.add(sequentialList);
}
String previousGroup = "";
int index = 0;
for (ITestNGMethod m : sequentialList) {
String[] g = m.getGroupsDependedUpon();
if (g.length > 0 && !m.getGroupsDependedUpon()[0].equals(previousGroup)) {
index++;
previousGroup = m.getGroupsDependedUpon()[0];
}
outSequentialList.put(index, m);
}
// System.out.println("Map list:" + mapList);
sl.addAll(sequentialAttributeList.values());
}
private boolean arrayContains(String[] array, String element) {
for (String a : array) {
if (element.equals(a)) {
return true;
}
}
return false;
}
/**
* Logs the beginning of the {@link #beforeRun()} .
*/
private void logStart() {
log(3,
"Running test " + m_testName + " on " + m_classMap.size() + " " + " classes, "
+ " included groups:[" + mapToString(m_xmlMethodSelector.getIncludedGroups())
+ "] excluded groups:[" + mapToString(m_xmlMethodSelector.getExcludedGroups()) + "]");
if (getVerbose() >= 3) {
for (ITestClass tc : m_classMap.values()) {
((TestClass) tc).dump();
}
}
}
/**
* Trigger the start/finish event.
*
* @param isStart <tt>true</tt> if the event is for start, <tt>false</tt> 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<String, String> ig= m_xmlMethodSelector.getIncludedGroups();
String[] result= ig.values().toArray((new String[ig.size()]));
return result;
}
@Override
public String[] getExcludedGroups() {
Map<String, String> eg= m_xmlMethodSelector.getExcludedGroups();
String[] result= eg.values().toArray((new String[eg.size()]));
return result;
}
@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<ITestNGMethod> getExcludedMethods() {
Map<ITestNGMethod, ITestNGMethod> 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;
}
//
// ITestContext
/////
/////
// ITestResultNotifier
//
@Override
public void addPassedTest(ITestNGMethod tm, ITestResult tr) {
m_passedTests.addResult(tr, tm);
}
@Override
public Set<ITestResult> getPassedTests(ITestNGMethod tm) {
return m_passedTests.getResults(tm);
}
@Override
public Set<ITestResult> getFailedTests(ITestNGMethod tm) {
return m_failedTests.getResults(tm);
}
@Override
public Set<ITestResult> 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) {
synchronized(m_invokedMethods) {
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<ITestListener> getTestListeners() {
return m_testListeners;
}
@Override
public List<IConfigurationListener> getConfigurationListeners() {
return m_configurationListeners;
}
//
// ITestResultNotifier
/////
private void logFailedTest(ITestNGMethod method,
ITestResult tr,
boolean withinSuccessPercentage) {
/*
* We should not remove a passed method from m_passedTests so that we can
* account for the passed instances of this test method.
*/
//m_passedTests.removeResult(method);
if (withinSuccessPercentage) {
m_failedButWithinSuccessPercentageTests.addResult(tr, method);
}
else {
m_failedTests.addResult(tr, method);
}
}
private String mapToString(Map<?, ?> m) {
StringBuffer result= new StringBuffer();
for (Object o : m.values()) {
result.append(o.toString()).append(" ");
}
return result.toString();
}
private void log(int level, String s) {
Utils.log("TestRunner", level, s);
}
public static int getVerbose() {
return m_verbose;
}
public void setVerbose(int n) {
m_verbose = n;
}
private void log(String s) {
Utils.log("TestRunner", 2, s);
}
/////
// Listeners
//
public void addListener(Object listener) {
if(listener instanceof ITestListener) {
addTestListener((ITestListener) listener);
}
if(listener instanceof IConfigurationListener) {
addConfigurationListener((IConfigurationListener) listener);
}
}
public void addTestListener(ITestListener il) {
m_testListeners.add(il);
}
private void addConfigurationListener(IConfigurationListener icl) {
m_configurationListeners.add(icl);
}
//
// Listeners
/////
private List<InvokedMethod> m_invokedMethods = Lists.newArrayList();
private void dumpInvokedMethods() {
System.out.println("\n*********** INVOKED METHODS\n");
for (IInvokedMethod im : m_invokedMethods) {
if (im.isTestMethod()) {
System.out.print("\t\t");
}
else if (im.isConfigurationMethod()) {
System.out.print("\t");
}
else {
continue;
}
System.out.println("" + im);
}
System.out.println("\n***********\n");
}
public List<ITestNGMethod> getInvokedMethods() {
List<ITestNGMethod> result= Lists.newArrayList();
synchronized(m_invokedMethods) {
for (IInvokedMethod im : m_invokedMethods) {
ITestNGMethod tm= im.getTestMethod();
tm.setDate(im.getDate());
result.add(tm);
}
}
return result;
}
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());
}
}
public void setMethodInterceptor(IMethodInterceptor methodInterceptor) {
m_methodInterceptor = 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<String> getAttributeNames() {
return m_attributes.getAttributeNames();
}
@Override
public Object removeAttribute(String name) {
return m_attributes.removeAttribute(name);
}
private ListMultiMap<Class<? extends Module>, Module> m_guiceModules = Maps.newListMultiMap();
@Override
public List<Module> getGuiceModules(Class<? extends Module> cls) {
List<Module> result = m_guiceModules.get(cls);
return result;
}
@Override
public void addGuiceModule(Class<? extends Module> cls, Module module) {
m_guiceModules.put(cls, module);
}
private Map<List<Module>, Injector> m_injectors = Maps.newHashMap();
@Override
public Injector getInjector(List<Module> moduleInstances) {
return m_injectors .get(moduleInstances);
}
@Override
public void addInjector(List<Module> moduleInstances, Injector injector) {
m_injectors.put(moduleInstances, injector);
}
} // TestRunner