Skip to content

Commit

Permalink
Allow listeners to be disabled at runtime
Browse files Browse the repository at this point in the history
Closes #2381
  • Loading branch information
krmahadevan committed Mar 9, 2024
1 parent 438674c commit c0175cc
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 66 deletions.
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Current (7.10.0)
Fixed: GITHUB-2381: Controlling the inclusion of the listener at runtime (Krishnan Mahadevan)
Fixed: GITHUB:3084: Document project's PGP artifact signing keys (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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@
*
* @author cbeust
*/
public interface ITestNGListener {}
public interface ITestNGListener {

/** @return - <code>true</code> if the current listener can be considered for execution. */
default boolean isEnabled() {
return true;
}
}
20 changes: 9 additions & 11 deletions testng-core/src/main/java/org/testng/SuiteRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -237,18 +237,16 @@ public ITestListener getExitCodeListener() {

private void invokeListeners(boolean start) {
if (start) {
for (ISuiteListener sl :
ListenerOrderDeterminer.order(
listeners.values(), this.configuration.getListenerComparator())) {
sl.onStart(this);
}
ListenerOrderDeterminer.order(listeners.values(), this.configuration.getListenerComparator())
.stream()
.filter(ITestNGListener::isEnabled)
.forEach(it -> it.onStart(this));
} else {
List<ISuiteListener> suiteListenersReversed =
ListenerOrderDeterminer.reversedOrder(
listeners.values(), this.configuration.getListenerComparator());
for (ISuiteListener sl : suiteListenersReversed) {
sl.onFinish(this);
}
ListenerOrderDeterminer.reversedOrder(
listeners.values(), this.configuration.getListenerComparator())
.stream()
.filter(ITestNGListener::isEnabled)
.forEach(it -> it.onFinish(this));
}
}

Expand Down
19 changes: 10 additions & 9 deletions testng-core/src/main/java/org/testng/TestNG.java
Original file line number Diff line number Diff line change
Expand Up @@ -1112,28 +1112,26 @@ protected List<ISuite> runSuites() {
private void runSuiteAlterationListeners() {
Collection<IAlterSuiteListener> original =
sort(m_alterSuiteListeners.values(), m_configuration.getListenerComparator());
for (IAlterSuiteListener l : original) {
l.alter(m_suites);
}
original.stream().filter(ITestNGListener::isEnabled).forEach(it -> it.alter(m_suites));
}

private void runExecutionListeners(boolean start) {
List<IExecutionListener> executionListeners =
ListenerOrderDeterminer.order(
m_configuration.getExecutionListeners(), m_configuration.getListenerComparator());
if (start) {
for (IExecutionListener l : executionListeners) {
l.onExecutionStart();
}
executionListeners.stream()
.filter(ITestNGListener::isEnabled)
.forEach(IExecutionListener::onExecutionStart);
// Invoke our exit code listener after all the user's listeners have run.
exitCodeListener.onExecutionStart();
} else {
List<IExecutionListener> executionListenersReversed =
ListenerOrderDeterminer.reversedOrder(
m_configuration.getExecutionListeners(), m_configuration.getListenerComparator());
for (IExecutionListener l : executionListenersReversed) {
l.onExecutionFinish();
}
executionListenersReversed.stream()
.filter(ITestNGListener::isEnabled)
.forEach(IExecutionListener::onExecutionFinish);
// Invoke our exit code listener after all the user's listeners have run.
exitCodeListener.onExecutionFinish();
}
Expand All @@ -1152,6 +1150,9 @@ private void generateReports(List<ISuite> suiteRunners) {
// whatever changes were done by a user's reporting listener
reporters.add(exitCodeListener);
for (IReporter reporter : reporters) {
if (!reporter.isEnabled()) {
continue;
}
try {
long start = System.currentTimeMillis();
reporter.generateReport(m_suites, suiteRunners, m_outputDir);
Expand Down
27 changes: 15 additions & 12 deletions testng-core/src/main/java/org/testng/TestRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,9 @@ private ITestNGMethod[] intercept(ITestNGMethod[] methods) {
List<IMethodInterceptor> original =
sort(m_methodInterceptors, m_configuration.getListenerComparator());
for (IMethodInterceptor m_methodInterceptor : original) {
methodInstances = m_methodInterceptor.intercept(methodInstances, this);
if (m_methodInterceptor.isEnabled()) {
methodInstances = m_methodInterceptor.intercept(methodInstances, this);
}
}

List<ITestNGMethod> result = MethodHelper.methodInstancesToMethods(methodInstances);
Expand Down Expand Up @@ -853,19 +855,18 @@ private void logStart() {
*/
private void fireEvent(boolean isStart) {
if (isStart) {
for (ITestListener itl :
ListenerOrderDeterminer.order(m_testListeners, m_configuration.getListenerComparator())) {
itl.onStart(this);
}
ListenerOrderDeterminer.order(m_testListeners, m_configuration.getListenerComparator())
.stream()
.filter(ITestNGListener::isEnabled)
.forEach(it -> it.onStart(this));
this.exitCodeListener.onStart(this);

} else {
List<ITestListener> testListenersReversed =
ListenerOrderDeterminer.reversedOrder(
m_testListeners, m_configuration.getListenerComparator());
for (ITestListener itl : testListenersReversed) {
itl.onFinish(this);
}
ListenerOrderDeterminer.reversedOrder(
m_testListeners, m_configuration.getListenerComparator())
.stream()
.filter(ITestNGListener::isEnabled)
.forEach(it -> it.onFinish(this));
this.exitCodeListener.onFinish(this);
}
if (!isStart) {
Expand Down Expand Up @@ -1102,7 +1103,9 @@ public void addListener(ITestNGListener listener) {
if (listener instanceof IExecutionListener) {
IExecutionListener iel = (IExecutionListener) listener;
if (m_configuration.addExecutionListenerIfAbsent(iel)) {
iel.onExecutionStart();
if (iel.isEnabled()) {
iel.onExecutionStart();
}
}
}
if (listener instanceof IDataProviderListener) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.concurrent.ConcurrentHashMap;
import org.testng.IDynamicGraph;
import org.testng.IExecutionVisualiser;
import org.testng.ITestNGListener;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.collections.Sets;
Expand Down Expand Up @@ -142,7 +143,9 @@ public void setStatus(T node, Status status) {
throw new IllegalArgumentException("Unsupported status: " + status);
}

this.visualisers.forEach(visualiser -> visualiser.consumeDotDefinition(toDot()));
this.visualisers.stream()
.filter(ITestNGListener::isEnabled)
.forEach(visualiser -> visualiser.consumeDotDefinition(toDot()));
}

/** @return the number of nodes in this graph. */
Expand Down
36 changes: 21 additions & 15 deletions testng-core/src/main/java/org/testng/internal/Parameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import java.util.*;
import org.testng.DataProviderHolder;
import org.testng.IDataProviderInterceptor;
import org.testng.IDataProviderListener;
import org.testng.IDataProviderMethod;
import org.testng.IRetryDataProvider;
import org.testng.ITestClass;
import org.testng.ITestContext;
import org.testng.ITestNGListener;
import org.testng.ITestNGMethod;
import org.testng.ITestObjectFactory;
import org.testng.ITestResult;
Expand Down Expand Up @@ -799,10 +799,12 @@ public static ParameterHolder handleParameters(
RuntimeException thrownException;
do {

for (IDataProviderListener dataProviderListener : holder.getListeners()) {
dataProviderListener.beforeDataProviderExecution(
dataProviderMethod, testMethod, methodParams.context);
}
holder.getListeners().stream()
.filter(ITestNGListener::isEnabled)
.forEach(
it ->
it.beforeDataProviderExecution(
dataProviderMethod, testMethod, methodParams.context));

try {
initParams =
Expand All @@ -817,9 +819,9 @@ public static ParameterHolder handleParameters(
shouldRetry = false;
thrownException = null;
} catch (RuntimeException e) {
for (IDataProviderListener each : holder.getListeners()) {
each.onDataProviderFailure(testMethod, methodParams.context, e);
}
holder.getListeners().stream()
.filter(ITestNGListener::isEnabled)
.forEach(it -> it.onDataProviderFailure(testMethod, methodParams.context, e));
if (shouldRetry) {
shouldRetry = retry.retry(dataProviderMethod);
thrownException = e;
Expand All @@ -840,10 +842,12 @@ public static ParameterHolder handleParameters(
throw thrownException;
}

for (IDataProviderListener dataProviderListener : holder.getListeners()) {
dataProviderListener.afterDataProviderExecution(
dataProviderMethod, testMethod, methodParams.context);
}
holder.getListeners().stream()
.filter(ITestNGListener::isEnabled)
.forEach(
it ->
it.afterDataProviderExecution(
dataProviderMethod, testMethod, methodParams.context));

// If the data provider is restricting the indices to return, filter them out
final List<Integer> allIndices = new ArrayList<>();
Expand All @@ -855,9 +859,11 @@ public static ParameterHolder handleParameters(

testMethod.setMoreInvocationChecker(filteredParameters::hasNext);
for (IDataProviderInterceptor interceptor : holder.getInterceptors()) {
filteredParameters =
interceptor.intercept(
filteredParameters, dataProviderMethod, testMethod, methodParams.context);
if (interceptor.isEnabled()) {
filteredParameters =
interceptor.intercept(
filteredParameters, dataProviderMethod, testMethod, methodParams.context);
}
}

if (dataProviderMethod instanceof DataProviderMethodRemovable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ private static void ignoreInternalGradleException(Exception e) {
*/
public static void runTestListeners(ITestResult tr, List<ITestListener> listeners) {
for (ITestListener itl : listeners) {
if (!itl.isEnabled()) {
continue;
}
switch (tr.getStatus()) {
case ITestResult.SKIP:
itl.onTestSkipped(tr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,20 +166,32 @@ private void transform(
if (m_transformer instanceof org.testng.internal.annotations.IAnnotationTransformer) {
org.testng.internal.annotations.IAnnotationTransformer transformer =
(org.testng.internal.annotations.IAnnotationTransformer) m_transformer;
transformer.transform(
(ITestAnnotation) a, testClass, testConstructor, testMethod, whichClass);
if (transformer.isEnabled()) {
transformer.transform(
(ITestAnnotation) a, testClass, testConstructor, testMethod, whichClass);
}
} else {
m_transformer.transform((ITestAnnotation) a, testClass, testConstructor, testMethod);
if (m_transformer.isEnabled()) {
m_transformer.transform((ITestAnnotation) a, testClass, testConstructor, testMethod);
}
}
} else if (a instanceof IConfigurationAnnotation) {
IConfigurationAnnotation configuration = (IConfigurationAnnotation) a;
m_transformer.transform(configuration, testClass, testConstructor, testMethod);
if (m_transformer.isEnabled()) {
m_transformer.transform(configuration, testClass, testConstructor, testMethod);
}
} else if (a instanceof IDataProviderAnnotation) {
m_transformer.transform((IDataProviderAnnotation) a, testMethod);
if (m_transformer.isEnabled()) {
m_transformer.transform((IDataProviderAnnotation) a, testMethod);
}
} else if (a instanceof IFactoryAnnotation) {
m_transformer.transform((IFactoryAnnotation) a, testMethod);
if (m_transformer.isEnabled()) {
m_transformer.transform((IFactoryAnnotation) a, testMethod);
}
} else if (a instanceof IListenersAnnotation) {
m_transformer.transform((IListenersAnnotation) a, testClass);
if (m_transformer.isEnabled()) {
m_transformer.transform((IListenersAnnotation) a, testClass);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public InvokedMethodListenerInvoker(
*/
public void invokeListener(
IInvokedMethodListener listenerInstance, IInvokedMethod invokedMethod) {
if (!listenerInstance.isEnabled()) {
return;
}
if (this.m_listenerMethod == BEFORE_INVOCATION) {
listenerInstance.beforeInvocation(invokedMethod, m_testResult);
listenerInstance.beforeInvocation(invokedMethod, m_testResult, m_testContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.testng.IMethodInstance;
import org.testng.ITestClass;
import org.testng.ITestContext;
import org.testng.ITestNGListener;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.collections.Lists;
Expand Down Expand Up @@ -167,11 +168,9 @@ protected void invokeBeforeClassMethods(ITestClass testClass, IMethodInstance mi
Object instance = mi.getInstance();
if (!instances.contains(instance)) {
instances.add(instance);
List<IClassListener> original =
sort(m_listeners, m_configInvoker.getConfiguration().getListenerComparator());
for (IClassListener listener : original) {
listener.onBeforeClass(testClass);
}
sort(m_listeners, m_configInvoker.getConfiguration().getListenerComparator()).stream()
.filter(ITestNGListener::isEnabled)
.forEach(it -> it.onBeforeClass(testClass));
ConfigMethodArguments attributes =
new Builder()
.forTestClass(testClass)
Expand Down Expand Up @@ -235,11 +234,9 @@ private void invokeAfterClassConfigurations(ITestClass testClass, List<Object> i
}

private void invokeListenersOnAfterClass(ITestClass testClass, List<IClassListener> listeners) {
List<IClassListener> original =
sort(listeners, m_configInvoker.getConfiguration().getListenerComparator());
for (IClassListener listener : original) {
listener.onAfterClass(testClass);
}
sort(listeners, m_configInvoker.getConfiguration().getListenerComparator()).stream()
.filter(ITestNGListener::isEnabled)
.forEach(it -> it.onAfterClass(testClass));
}

protected int indexOf(ITestNGMethod tm, ITestNGMethod[] allTestMethods) {
Expand Down
10 changes: 10 additions & 0 deletions testng-core/src/test/java/test/listeners/ListenersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.testng.internal.ExitCode;
import org.testng.xml.XmlSuite;
import test.SimpleBaseTest;
import test.listeners.issue2381.SampleGlobalListener;
import test.listeners.issue2638.DummyInvokedMethodListener;
import test.listeners.issue2638.TestClassASample;
import test.listeners.issue2638.TestClassBSample;
Expand Down Expand Up @@ -521,6 +522,15 @@ public void testSkipStatusInBeforeAndAfterConfigurationMethod(
assertThat(listener.getLogs()).containsExactlyElementsOf(expected);
}

@Test(description = "GITHUB-2381")
public void ensureListenersCanBeDisabled() {
TestNG testng = create(test.listeners.issue2381.TestClassSample.class);
SampleGlobalListener listener = new SampleGlobalListener();
testng.addListener(listener);
testng.run();
assertThat(listener.getLogs()).isEmpty();
}

private void setupTest(boolean addExplicitListener) {
TestNG testng = new TestNG();
XmlSuite xmlSuite = createXmlSuite("Xml_Suite");
Expand Down

0 comments on commit c0175cc

Please sign in to comment.