| 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 |