Skip to content

Commit

Permalink
Map object to configurations (#3089)
Browse files Browse the repository at this point in the history
  • Loading branch information
krmahadevan committed Mar 14, 2024
1 parent 19cd580 commit 23bb95f
Show file tree
Hide file tree
Showing 16 changed files with 276 additions and 73 deletions.
5 changes: 3 additions & 2 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Current (7.10.0)
Fixed: GITHUB:3084: Document project's PGP artifact signing keys (Krishnan Mahadevan)
Fixed: GITHUB-3082: IInvokedMethodListener Iinvoked method does not return correct instance during @BeforeMethod, @AfterMethod and @AfterClass (Krishnan Mahadevan)
Fixed: GITHUB-3084: Document project's PGP artifact signing keys (Krishnan Mahadevan)
Fixed: GITHUB-3079: Associate a unique id with every test class object instantiated by TestNG (Krishnan Mahadevan)
Fixed: GITHUB:3040: replace the usages of synchronized with ReentrantLock (Krishnan Mahadevan)
Fixed: GITHUB-3040: replace the usages of synchronized with ReentrantLock (Krishnan Mahadevan)
Fixed: GITHUB-3041: TestNG 7.x DataProvider works in opposite to TestNG 6.x when retrying tests. (Krishnan Mahadevan)
Fixed: GITHUB-3066: How to dynamically adjust the number of TestNG threads after IExecutorFactory is deprecated? (Krishnan Mahadevan)
New: GITHUB-2874: Allow users to define ordering for TestNG listeners (Krishnan Mahadevan)
Expand Down
7 changes: 1 addition & 6 deletions testng-core/src/main/java/org/testng/ClassMethodMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@ public ClassMethodMap(List<ITestNGMethod> methods, XmlMethodSelector xmlMethodSe
}

Object instance = m.getInstance();
Collection<ITestNGMethod> l = classMap.get(instance);
if (l == null) {
l = new ConcurrentLinkedQueue<>();
classMap.put(instance, l);
}
l.add(m);
classMap.computeIfAbsent(instance, k -> new ConcurrentLinkedQueue<>()).add(m);
}
}

Expand Down
32 changes: 25 additions & 7 deletions testng-core/src/main/java/org/testng/TestClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,22 @@ class TestClass extends NoOpTestClass implements ITestClass, ITestClassConfigInf
private final IdentityHashMap<Object, List<ITestNGMethod>> beforeClassConfig =
new IdentityHashMap<>();

private final IdentityHashMap<Object, List<ITestNGMethod>> afterClassConfig =
new IdentityHashMap<>();

@Override
public List<ITestNGMethod> getAllBeforeClassMethods() {
return beforeClassConfig
.values()
return getAllClassLevelConfigs(beforeClassConfig);
}

@Override
public List<ITestNGMethod> getAllAfterClassMethods() {
return getAllClassLevelConfigs(afterClassConfig);
}

private static List<ITestNGMethod> getAllClassLevelConfigs(
IdentityHashMap<Object, List<ITestNGMethod>> map) {
return map.values()
.parallelStream()
.reduce(
(a, b) -> {
Expand All @@ -51,6 +63,11 @@ public List<ITestNGMethod> getInstanceBeforeClassMethods(Object instance) {
return beforeClassConfig.get(instance);
}

@Override
public List<ITestNGMethod> getInstanceAfterClassMethods(Object instance) {
return afterClassConfig.get(instance);
}

private static final Logger LOG = Logger.getLogger(TestClass.class);

protected TestClass(
Expand Down Expand Up @@ -192,7 +209,7 @@ private void initMethods() {
xmlTest,
eachInstance);
Object instance = IParameterInfo.embeddedInstance(eachInstance.getInstance());
beforeClassConfig.put(instance, Arrays.asList(m_beforeClassMethods));
beforeClassConfig.put(instance, m_beforeClassMethods);
m_afterClassMethods =
ConfigurationMethod.createClassConfigurationMethods(
objectFactory,
Expand All @@ -201,6 +218,7 @@ private void initMethods() {
false,
xmlTest,
eachInstance);
afterClassConfig.put(instance, m_afterClassMethods);
m_beforeGroupsMethods =
ConfigurationMethod.createBeforeConfigurationMethods(
objectFactory,
Expand All @@ -215,22 +233,22 @@ private void initMethods() {
annotationFinder,
false,
eachInstance);
m_beforeTestMethods =
m_beforeTestMethods.addAll(
ConfigurationMethod.createTestMethodConfigurationMethods(
objectFactory,
testMethodFinder.getBeforeTestMethods(m_testClass),
annotationFinder,
true,
xmlTest,
eachInstance);
m_afterTestMethods =
eachInstance));
m_afterTestMethods.addAll(
ConfigurationMethod.createTestMethodConfigurationMethods(
objectFactory,
testMethodFinder.getAfterTestMethods(m_testClass),
annotationFinder,
false,
xmlTest,
eachInstance);
eachInstance));
}
}

Expand Down
16 changes: 11 additions & 5 deletions testng-core/src/main/java/org/testng/TestRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -486,15 +486,13 @@ private void initMethods() {
// 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(
((ITestClassConfigInfo) tc).getAllBeforeClassMethods().toArray(new ITestNGMethod[0]),
tc,
beforeClassMethods);
fixMethodsWithClass(beforeClassConfigMethods(tc), tc, beforeClassMethods);
fixMethodsWithClass(tc.getBeforeTestMethods(), tc, null);
fixMethodsWithClass(tc.getAfterTestMethods(), tc, null);
fixMethodsWithClass(tc.getAfterClassMethods(), tc, afterClassMethods);
fixMethodsWithClass(afterClassConfigMethods(tc), tc, afterClassMethods);
fixMethodsWithClass(tc.getBeforeSuiteMethods(), tc, beforeSuiteMethods);
fixMethodsWithClass(tc.getAfterSuiteMethods(), tc, afterSuiteMethods);
fixMethodsWithClass(tc.getBeforeTestConfigurationMethods(), tc, beforeXmlTestMethods);
Expand Down Expand Up @@ -558,6 +556,14 @@ private void initMethods() {
comparator);
}

private static ITestNGMethod[] beforeClassConfigMethods(ITestClass tc) {
return ITestClassConfigInfo.allBeforeClassMethods(tc).toArray(ITestNGMethod[]::new);
}

private static ITestNGMethod[] afterClassConfigMethods(ITestClass tc) {
return ITestClassConfigInfo.allAfterClassMethods(tc).toArray(ITestNGMethod[]::new);
}

private ITestNGMethod[] computeAndGetAllTestMethods() {
List<ITestNGMethod> testMethods = Lists.newArrayList();
for (ITestClass tc : m_classMap.values()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.testng.ITestNGMethod;
import org.testng.ITestObjectFactory;
import org.testng.annotations.IAnnotation;
Expand Down Expand Up @@ -143,7 +144,7 @@ public ConfigurationMethod(
setXmlTest(xmlTest);
}

private static ITestNGMethod[] createMethods(
private static List<ITestNGMethod> createMethods(
ITestObjectFactory objectFactory,
ITestNGMethod[] methods,
IAnnotationFinder finder,
Expand Down Expand Up @@ -188,10 +189,10 @@ private static ITestNGMethod[] createMethods(
instance));
}

return result.toArray(new ITestNGMethod[0]);
return result;
}

public static ITestNGMethod[] createSuiteConfigurationMethods(
public static List<ITestNGMethod> createSuiteConfigurationMethods(
ITestObjectFactory objectFactory,
ITestNGMethod[] methods,
IAnnotationFinder annotationFinder,
Expand All @@ -214,7 +215,7 @@ public static ITestNGMethod[] createSuiteConfigurationMethods(
instance);
}

public static ITestNGMethod[] createTestConfigurationMethods(
public static List<ITestNGMethod> createTestConfigurationMethods(
ITestObjectFactory objectFactory,
ITestNGMethod[] methods,
IAnnotationFinder annotationFinder,
Expand All @@ -237,7 +238,7 @@ public static ITestNGMethod[] createTestConfigurationMethods(
instance);
}

public static ITestNGMethod[] createClassConfigurationMethods(
public static List<ITestNGMethod> createClassConfigurationMethods(
ITestObjectFactory objectFactory,
ITestNGMethod[] methods,
IAnnotationFinder annotationFinder,
Expand Down Expand Up @@ -291,7 +292,7 @@ public static ITestNGMethod[] createBeforeConfigurationMethods(
return result;
}

public static ITestNGMethod[] createAfterConfigurationMethods(
public static List<ITestNGMethod> createAfterConfigurationMethods(
ITestObjectFactory objectFactory,
ITestNGMethod[] methods,
IAnnotationFinder annotationFinder,
Expand All @@ -318,10 +319,10 @@ public static ITestNGMethod[] createAfterConfigurationMethods(
isBefore ? m.getBeforeGroups() : m.getAfterGroups(),
null,
instance))
.toArray(ITestNGMethod[]::new);
.collect(Collectors.toList());
}

public static ITestNGMethod[] createTestMethodConfigurationMethods(
public static List<ITestNGMethod> createTestMethodConfigurationMethods(
ITestObjectFactory objectFactory,
ITestNGMethod[] methods,
IAnnotationFinder annotationFinder,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.testng.internal;

import java.util.List;
import org.testng.ITestClass;
import org.testng.ITestNGMethod;
import org.testng.collections.Lists;

Expand All @@ -11,17 +12,31 @@ public interface ITestClassConfigInfo {
*
* @return all before class config methods
*/
default List<ITestNGMethod> getAllBeforeClassMethods() {
return Lists.newArrayList();
}
List<ITestNGMethod> getAllBeforeClassMethods();

List<ITestNGMethod> getAllAfterClassMethods();

/**
* Query the instance before class methods from config methods map.
*
* @param instance object hashcode
* @return All before class methods of instance
*/
default List<ITestNGMethod> getInstanceBeforeClassMethods(Object instance) {
List<ITestNGMethod> getInstanceBeforeClassMethods(Object instance);

List<ITestNGMethod> getInstanceAfterClassMethods(Object instance);

static List<ITestNGMethod> allBeforeClassMethods(ITestClass tc) {
if (tc instanceof ITestClassConfigInfo) {
return ((ITestClassConfigInfo) tc).getAllBeforeClassMethods();
}
return Lists.newArrayList();
}

static List<ITestNGMethod> allAfterClassMethods(ITestClass tc) {
if (tc instanceof ITestClassConfigInfo) {
return ((ITestClassConfigInfo) tc).getAllAfterClassMethods();
}
return Lists.newArrayList();
}
}
60 changes: 31 additions & 29 deletions testng-core/src/main/java/org/testng/internal/NoOpTestClass.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.testng.internal;

import java.util.ArrayList;
import java.util.List;
import org.testng.ITestClass;
import org.testng.ITestNGMethod;
import org.testng.xml.XmlClass;
Expand All @@ -10,17 +12,17 @@ public class NoOpTestClass implements ITestClass, IObject {
protected Class<?> m_testClass = null;

// Test methods
protected ITestNGMethod[] m_beforeClassMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_beforeTestMethods = new ITestNGMethod[0];
protected List<ITestNGMethod> m_beforeClassMethods = new ArrayList<>();
protected List<ITestNGMethod> m_beforeTestMethods = new ArrayList<>();
protected ITestNGMethod[] m_testMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_afterClassMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_afterTestMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_beforeSuiteMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_afterSuiteMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_beforeTestConfMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_afterTestConfMethods = new ITestNGMethod[0];
protected List<ITestNGMethod> m_afterClassMethods = new ArrayList<>();
protected List<ITestNGMethod> m_afterTestMethods = new ArrayList<>();
protected List<ITestNGMethod> m_beforeSuiteMethods = new ArrayList<>();
protected List<ITestNGMethod> m_afterSuiteMethods = new ArrayList<>();
protected List<ITestNGMethod> m_beforeTestConfMethods = new ArrayList<>();
protected List<ITestNGMethod> m_afterTestConfMethods = new ArrayList<>();
protected ITestNGMethod[] m_beforeGroupsMethods = new ITestNGMethod[0];
protected ITestNGMethod[] m_afterGroupsMethods = new ITestNGMethod[0];
protected List<ITestNGMethod> m_afterGroupsMethods = new ArrayList<>();

private final IdentifiableObject[] m_instances;
private final long[] m_instanceHashes;
Expand All @@ -37,52 +39,52 @@ protected NoOpTestClass() {

public NoOpTestClass(ITestClass testClass) {
m_testClass = testClass.getRealClass();
m_beforeSuiteMethods = testClass.getBeforeSuiteMethods();
m_beforeTestConfMethods = testClass.getBeforeTestConfigurationMethods();
m_beforeSuiteMethods = List.of(testClass.getBeforeSuiteMethods());
m_beforeTestConfMethods = List.of(testClass.getBeforeTestConfigurationMethods());
m_beforeGroupsMethods = testClass.getBeforeGroupsMethods();
m_beforeClassMethods = testClass.getBeforeClassMethods();
m_beforeTestMethods = testClass.getBeforeTestMethods();
m_afterSuiteMethods = testClass.getAfterSuiteMethods();
m_afterTestConfMethods = testClass.getAfterTestConfigurationMethods();
m_afterGroupsMethods = testClass.getAfterGroupsMethods();
m_afterClassMethods = testClass.getAfterClassMethods();
m_afterTestMethods = testClass.getAfterTestMethods();
m_beforeClassMethods = List.of(testClass.getBeforeClassMethods());
m_beforeTestMethods = List.of(testClass.getBeforeTestMethods());
m_afterSuiteMethods = List.of(testClass.getAfterSuiteMethods());
m_afterTestConfMethods = List.of(testClass.getAfterTestConfigurationMethods());
m_afterGroupsMethods = List.of(testClass.getAfterGroupsMethods());
m_afterClassMethods = List.of(testClass.getAfterClassMethods());
m_afterTestMethods = List.of(testClass.getAfterTestMethods());
m_instances = IObject.objects(testClass, true);
m_instanceHashes = IObject.instanceHashCodes(testClass);
m_xmlTest = testClass.getXmlTest();
m_xmlClass = testClass.getXmlClass();
}

public void setBeforeTestMethods(ITestNGMethod[] beforeTestMethods) {
m_beforeTestMethods = beforeTestMethods;
m_beforeTestMethods = List.of(beforeTestMethods);
}

public void setAfterTestMethod(ITestNGMethod[] afterTestMethods) {
m_afterTestMethods = afterTestMethods;
m_afterTestMethods = List.of(afterTestMethods);
}

/** @return Returns the afterClassMethods. */
@Override
public ITestNGMethod[] getAfterClassMethods() {
return m_afterClassMethods;
return m_afterClassMethods.toArray(ITestNGMethod[]::new);
}

/** @return Returns the afterTestMethods. */
@Override
public ITestNGMethod[] getAfterTestMethods() {
return m_afterTestMethods;
return m_afterTestMethods.toArray(ITestNGMethod[]::new);
}

/** @return Returns the beforeClassMethods. */
@Override
public ITestNGMethod[] getBeforeClassMethods() {
return m_beforeClassMethods;
return m_beforeClassMethods.toArray(ITestNGMethod[]::new);
}

/** @return Returns the beforeTestMethods. */
@Override
public ITestNGMethod[] getBeforeTestMethods() {
return m_beforeTestMethods;
return m_beforeTestMethods.toArray(ITestNGMethod[]::new);
}

/** @return Returns the testMethods. */
Expand All @@ -93,22 +95,22 @@ public ITestNGMethod[] getTestMethods() {

@Override
public ITestNGMethod[] getBeforeSuiteMethods() {
return m_beforeSuiteMethods;
return m_beforeSuiteMethods.toArray(ITestNGMethod[]::new);
}

@Override
public ITestNGMethod[] getAfterSuiteMethods() {
return m_afterSuiteMethods;
return m_afterSuiteMethods.toArray(ITestNGMethod[]::new);
}

@Override
public ITestNGMethod[] getBeforeTestConfigurationMethods() {
return m_beforeTestConfMethods;
return m_beforeTestConfMethods.toArray(ITestNGMethod[]::new);
}

@Override
public ITestNGMethod[] getAfterTestConfigurationMethods() {
return m_afterTestConfMethods;
return m_afterTestConfMethods.toArray(ITestNGMethod[]::new);
}

/** @return all @Configuration methods that should be invoked before certain groups */
Expand All @@ -120,7 +122,7 @@ public ITestNGMethod[] getBeforeGroupsMethods() {
/** @return all @Configuration methods that should be invoked after certain groups */
@Override
public ITestNGMethod[] getAfterGroupsMethods() {
return m_afterGroupsMethods;
return m_afterGroupsMethods.toArray(ITestNGMethod[]::new);
}

/** @see org.testng.internal.IObject#getInstanceHashCodes() */
Expand Down

0 comments on commit 23bb95f

Please sign in to comment.