package org.testng.internal;
import org.testng.DependencyMap;
import org.testng.ITestNGMethod;
import org.testng.TestNGException;
import org.testng.TestRunner;
import org.testng.collections.ListMultiMap;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlSuite.ParallelMode;
import org.testng.xml.XmlTest;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public final class DynamicGraphHelper {
private DynamicGraphHelper() {
}
public static DynamicGraph<ITestNGMethod> createDynamicGraph(
ITestNGMethod[] methods, XmlTest xmlTest) {
DynamicGraph<ITestNGMethod> result = new DynamicGraph<>();
DependencyMap dependencyMap = new DependencyMap(methods);
boolean hasDependencies = false;
for (ITestNGMethod m : methods) {
boolean added = result.addNode(m);
if (!added) {
result.addNode(new WrappedTestNGMethod(m));
}
String[] dependentMethods = m.getMethodsDependedUpon();
for (String d : dependentMethods) {
ITestNGMethod dm = dependencyMap.getMethodDependingOn(d, m);
if (m != dm) {
result.addEdge(TestRunner.PriorityWeight.dependsOnMethods.ordinal(), m, dm);
}
}
String[] dependentGroups = m.getGroupsDependedUpon();
for (String d : dependentGroups) {
hasDependencies = true;
List<ITestNGMethod> dg = dependencyMap.getMethodsThatBelongTo(d, m);
if (dg == null) {
throw new TestNGException(
"Method \"" + m + "\" depends on nonexistent group \"" + d + "\"");
}
for (ITestNGMethod ddm : dg) {
result.addEdge(TestRunner.PriorityWeight.dependsOnGroups.ordinal(), m, ddm);
}
}
}
if (!hasDependencies
&& xmlTest.getParallel() == XmlSuite.ParallelMode.NONE
&& xmlTest.getPreserveOrder()) {
ListMultiMap<ITestNGMethod, ITestNGMethod> classDependencies =
createClassDependencies(methods, xmlTest);
for (Map.Entry<ITestNGMethod, List<ITestNGMethod>> es : classDependencies.entrySet()) {
for (ITestNGMethod dm : es.getValue()) {
result.addEdge(TestRunner.PriorityWeight.preserveOrder.ordinal(), dm, es.getKey());
}
}
}
if (canGroupByInstances(xmlTest)) {
ListMultiMap<ITestNGMethod, ITestNGMethod> instanceDependencies =
createInstanceDependencies(methods);
for (Map.Entry<ITestNGMethod, List<ITestNGMethod>> es : instanceDependencies.entrySet()) {
result.addEdges(
TestRunner.PriorityWeight.groupByInstance.ordinal(), es.getKey(), es.getValue());
}
}
return result;
}
private static Comparator<XmlClass> classComparator() {
return Comparator.comparingInt(XmlClass::getIndex);
}
private static boolean canGroupByInstances(XmlTest xmlTest) {
return xmlTest.getGroupByInstances() && ! xmlTest.getParallel().equals(ParallelMode.INSTANCES);
}
private static ListMultiMap<ITestNGMethod, ITestNGMethod> createClassDependencies(
ITestNGMethod[] methods, XmlTest test) {
Map<String, List<ITestNGMethod>> classes = Maps.newHashMap();
List<XmlClass> sortedClasses = Lists.newArrayList();
ListMultiMap<String, ITestNGMethod> methodsFromClass = Maps.newListMultiMap();
for (ITestNGMethod m : methods) {
methodsFromClass.put(m.getTestClass().getName(), m);
}
final List<XmlClass> classesWithMethods = test.getXmlClasses()
.stream()
.filter(xmlClass -> methodsFromClass.keySet().contains(xmlClass.getName()))
.collect(Collectors.toList());
for (XmlClass c : classesWithMethods) {
classes.put(c.getName(), new ArrayList<>());
if (!sortedClasses.contains(c)) {
sortedClasses.add(c);
}
}
sortedClasses.sort(classComparator());
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<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
for (ITestNGMethod m : methods) {
String name = m.getTestClass().getName();
Integer index = indexedClasses1.get(name);
if (index != null && index > 0) {
String classDependedUpon = indexedClasses2.get(index - 1);
List<ITestNGMethod> methodsDependedUpon = methodsFromClass.get(classDependedUpon);
for (ITestNGMethod mdu : methodsDependedUpon) {
result.put(mdu, m);
}
}
}
return result;
}
private static ListMultiMap<ITestNGMethod, ITestNGMethod> createInstanceDependencies(
ITestNGMethod[] methods) {
ListMultiMap<Object, ITestNGMethod> instanceMap = Maps.newSortedListMultiMap();
for (ITestNGMethod m : methods) {
instanceMap.put(m.getInstance(), m);
}
ListMultiMap<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
Object previousInstance = null;
for (Map.Entry<Object, List<ITestNGMethod>> es : instanceMap.entrySet()) {
if (previousInstance == null) {
previousInstance = es.getKey();
} else {
List<ITestNGMethod> previousMethods = instanceMap.get(previousInstance);
Object currentInstance = es.getKey();
List<ITestNGMethod> currentMethods = instanceMap.get(currentInstance);
for (ITestNGMethod cm : currentMethods) {
for (ITestNGMethod pm : previousMethods) {
result.put(cm, pm);
}
}
previousInstance = currentInstance;
}
}
return result;
}
}