Skip to content

Commit

Permalink
Temp commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeust committed Aug 4, 2011
1 parent 10a202a commit cc950e9
Show file tree
Hide file tree
Showing 19 changed files with 215 additions and 80 deletions.
169 changes: 131 additions & 38 deletions src/main/java/org/testng/TestRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,10 @@ private void initMethods() {
//
// 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);
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
Expand Down Expand Up @@ -717,7 +719,8 @@ private void privateRun(XmlTest xmlTest) {
|| XmlSuite.PARALLEL_CLASSES.equals(parallelMode)
|| XmlSuite.PARALLEL_INSTANCES.equals(parallelMode);

if (!parallel) {
// @@@
if (false) { // (!parallel) {
// sequential
computeTestLists(sequentialList, parallelList, sequentialMapList);

Expand Down Expand Up @@ -767,27 +770,40 @@ private void privateRun(XmlTest xmlTest) {
}
else {
// parallel
int threadCount = xmlTest.getThreadCount();
int threadCount = parallel ? xmlTest.getThreadCount() : 1;
// Make sure we create a graph based on the intercepted methods, otherwise an interceptor
// removing methods would cause the graph never to terminate (because it would expect
// termination from methods that never get invoked).
DynamicGraph<ITestNGMethod> graph = createDynamicGraph(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();
// if (parallel) {
if (graph.getNodeCount() > 0) {
GraphThreadPoolExecutor<ITestNGMethod> executor =
new GraphThreadPoolExecutor<ITestNGMethod>(graph, this,
threadCount, threadCount, 0, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
executor.run();
// if (parallel) {
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();
}
// }
}
}
// } else {
// List<ITestNGMethod> freeNodes = graph.getFreeNodes();
// while (! freeNodes.isEmpty()) {
// List<IWorker<ITestNGMethod>> runnables = createWorkers(freeNodes);
// for (IWorker<ITestNGMethod> r : runnables) {
// r.run();
// }
// freeNodes = graph.getFreeNodes();
// }
// }
}
}

Expand Down Expand Up @@ -869,7 +885,7 @@ public int compare(XmlClass arg0, XmlClass arg1) {
* be put in the same worker in order to run in the same thread.
*/
@Override
public List<IWorker<ITestNGMethod>> createWorkers(Set<ITestNGMethod> methods) {
public List<IWorker<ITestNGMethod>> createWorkers(List<ITestNGMethod> methods) {
List<IWorker<ITestNGMethod>> result;
if (XmlSuite.PARALLEL_INSTANCES.equals(m_xmlTest.getParallel())) {
result = createInstanceBasedParallelWorkers(methods);
Expand All @@ -882,7 +898,7 @@ public List<IWorker<ITestNGMethod>> createWorkers(Set<ITestNGMethod> methods) {
/**
* Create workers for parallel="classes" and similar cases.
*/
private List<IWorker<ITestNGMethod>> createClassBasedParallelWorkers(Set<ITestNGMethod> methods) {
private List<IWorker<ITestNGMethod>> createClassBasedParallelWorkers(List<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
Expand Down Expand Up @@ -949,7 +965,7 @@ private List<IWorker<ITestNGMethod>> createClassBasedParallelWorkers(Set<ITestNG
* Create workers for parallel="instances".
*/
private List<IWorker<ITestNGMethod>>
createInstanceBasedParallelWorkers(Set<ITestNGMethod> methods) {
createInstanceBasedParallelWorkers(List<ITestNGMethod> methods) {
List<IWorker<ITestNGMethod>> result = Lists.newArrayList();
ListMultiMap<Object, ITestNGMethod> lmm = Maps.newListMultiMap();
for (ITestNGMethod m : methods) {
Expand Down Expand Up @@ -1273,48 +1289,64 @@ private boolean containsString(Map<String, String> regexps, String group) {

private DynamicGraph<ITestNGMethod> createDynamicGraph(ITestNGMethod[] methods) {
DynamicGraph<ITestNGMethod> result = new DynamicGraph<ITestNGMethod>();
result.setComparator(new Comparator<ITestNGMethod>() {
@Override
public int compare(ITestNGMethod o1, ITestNGMethod o2) {
return o1.getPriority() - o2.getPriority();
}
});

// If preserve-order was specified and the class order is A, B
// create a new set of dependencies where each method of B depends
// on all the methods of A
ListMultiMap<ITestNGMethod, ITestNGMethod> classDependencies = null;
if ("true".equalsIgnoreCase(getCurrentXmlTest().getPreserveOrder())) {
classDependencies = createClassDependencies(methods, getCurrentXmlTest());
}

Map<String, ITestNGMethod> map = Maps.newHashMap();
ListMultiMap<String, ITestNGMethod> groups = Maps.newListMultiMap();

for (ITestNGMethod m : methods) {
map.put(m.getTestClass().getName() + "." + m.getMethodName(), m);
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);
}
// 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;
// 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);
}
}
}
}
// 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);
String shortMethodName = d.substring(d.lastIndexOf(".") + 1);
ITestNGMethod dm = map.get(shortMethodName);
if (dm == null) {
throw new TestNGException("Method \"" + m
+ "\" depends on nonexistent method \"" + d + "\"");
Expand All @@ -1339,6 +1371,67 @@ private DynamicGraph<ITestNGMethod> createDynamicGraph(ITestNGMethod[] methods)
}
}

// Preserve order
if (classDependencies != null) {
for (Map.Entry<ITestNGMethod, List<ITestNGMethod>> es : classDependencies.getEntrySet()) {
for (ITestNGMethod dm : es.getValue()) {
// System.out.println("@@@ Dep from:" + m + " to " + dm);
result.addEdge(dm, es.getKey());
}
}
}
}

List<ITestNGMethod> n = result.getFreeNodes();
return result;
}

private ListMultiMap<ITestNGMethod, ITestNGMethod> createClassDependencies(
ITestNGMethod[] methods, XmlTest test)
{

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();
}
});

Map<String, Integer> indexedClasses1 = Maps.newHashMap();
Map<Integer, String> indexedClasses2 = Maps.newHashMap();
int i = 0;
for (XmlClass c : sortedClasses) {
indexedClasses1.put(c.getName(), i);
indexedClasses2.put(i, c.getName());
i++;
}

ListMultiMap<String, ITestNGMethod> methodsFromClass = Maps.newListMultiMap();
for (ITestNGMethod m : methods) {
methodsFromClass.put(m.getTestClass().getName(), m);
}

ListMultiMap<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
for (ITestNGMethod m : methods) {
int index = indexedClasses1.get(m.getTestClass().getName());
if (index > 0) {
// Make this method depend on all the methods of the class in the previous
// index
String classDependedUpon = indexedClasses2.get(index - 1);
List<ITestNGMethod> methodsDependedUpon = methodsFromClass.get(classDependedUpon);
for (ITestNGMethod mdu : methodsDependedUpon) {
result.put(mdu, m);
}
}
}

return result;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/testng/internal/BaseTestMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,8 @@ protected IClass getIClass() {
* @return
*/
protected String getSignature() {
String cls = m_method.getDeclaringClass().getName();
String classLong = m_method.getDeclaringClass().getName();
String cls = classLong.substring(classLong.lastIndexOf(".") + 1);
StringBuffer result = new StringBuffer(cls + "." + m_method.getName() + "(");
int i = 0;
for (Class<?> p : m_method.getParameterTypes()) {
Expand Down
32 changes: 25 additions & 7 deletions src/main/java/org/testng/internal/DynamicGraph.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
package org.testng.internal;

import com.google.inject.internal.Lists;

import org.testng.collections.ListMultiMap;
import org.testng.collections.Maps;
import org.testng.internal.annotations.Sets;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

/**
* Representation of the graph of methods.
*/
public class DynamicGraph<T> {
private static final boolean DEBUG = true;
private static final boolean DEBUG = false;

private Set<T> m_nodesReady = Sets.newLinkedHashSet();
private Set<T> m_nodesRunning = Sets.newLinkedHashSet();
private Set<T> m_nodesFinished = Sets.newLinkedHashSet();

private Set<T> m_nodesReady = Sets.newHashSet();
private Set<T> m_nodesRunning = Sets.newHashSet();
private Set<T> m_nodesFinished = Sets.newHashSet();
private Comparator<? super T> m_nodeComparator = null;

private ListMultiMap<T, T> m_dependedUpon = Maps.newListMultiMap();
private ListMultiMap<T, T> m_dependingOn = Maps.newListMultiMap();
Expand All @@ -25,6 +31,14 @@ public static enum Status {
READY, RUNNING, FINISHED
}

/**
* Define a comparator for the nodes of this graph, which will be used
* to order the free nodes when they are asked.
*/
public void setComparator(Comparator<? super T> c) {
m_nodeComparator = c;
}

/**
* Add a node to the graph.
*/
Expand All @@ -46,8 +60,8 @@ public void addEdge(T from, T to) {
/**
* @return a set of all the nodes that don't depend on any other nodes.
*/
public Set<T> getFreeNodes() {
Set<T> result = Sets.newHashSet();
public List<T> getFreeNodes() {
List<T> result = Lists.newArrayList();
for (T m : m_nodesReady) {
// A node is free if...

Expand All @@ -58,6 +72,10 @@ public Set<T> getFreeNodes() {
result.add(m);
}
}
if (result != null && !result.isEmpty() && m_nodeComparator != null) {
Collections.sort(result, m_nodeComparator);
ppp("Nodes after sorting:" + result.get(0));
}
return result;
}

Expand Down Expand Up @@ -154,7 +172,7 @@ public String toDot() {
String RUNNING = "[style=filled color=green]";
String FINISHED = "[style=filled color=grey]";
StringBuilder result = new StringBuilder("digraph g {\n");
Set<T> freeNodes = getFreeNodes();
List<T> freeNodes = getFreeNodes();
String color;
for (T n : m_nodesReady) {
color = freeNodes.contains(n) ? FREE : "";
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/testng/internal/annotations/Sets.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package org.testng.internal.annotations;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class Sets {

public static <K> Set<K> newHashSet() {
return new HashSet<K>();
public static <T> Set<T> newHashSet() {
return new HashSet<T>();
}

public static <T> Set<T> newLinkedHashSet() {
return new LinkedHashSet<T>();
}

}

0 comments on commit cc950e9

Please sign in to comment.