Skip to content

Commit c0175cc

Browse files
committed
Allow listeners to be disabled at runtime
Closes #2381
1 parent 438674c commit c0175cc

File tree

14 files changed

+255
-66
lines changed

14 files changed

+255
-66
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Current (7.10.0)
2+
Fixed: GITHUB-2381: Controlling the inclusion of the listener at runtime (Krishnan Mahadevan)
23
Fixed: GITHUB:3084: Document project's PGP artifact signing keys (Krishnan Mahadevan)
34
Fixed: GITHUB:3040: replace the usages of synchronized with ReentrantLock (Krishnan Mahadevan)
45
Fixed: GITHUB-3041: TestNG 7.x DataProvider works in opposite to TestNG 6.x when retrying tests. (Krishnan Mahadevan)

testng-core-api/src/main/java/org/testng/ITestNGListener.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,10 @@
55
*
66
* @author cbeust
77
*/
8-
public interface ITestNGListener {}
8+
public interface ITestNGListener {
9+
10+
/** @return - <code>true</code> if the current listener can be considered for execution. */
11+
default boolean isEnabled() {
12+
return true;
13+
}
14+
}

testng-core/src/main/java/org/testng/SuiteRunner.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -237,18 +237,16 @@ public ITestListener getExitCodeListener() {
237237

238238
private void invokeListeners(boolean start) {
239239
if (start) {
240-
for (ISuiteListener sl :
241-
ListenerOrderDeterminer.order(
242-
listeners.values(), this.configuration.getListenerComparator())) {
243-
sl.onStart(this);
244-
}
240+
ListenerOrderDeterminer.order(listeners.values(), this.configuration.getListenerComparator())
241+
.stream()
242+
.filter(ITestNGListener::isEnabled)
243+
.forEach(it -> it.onStart(this));
245244
} else {
246-
List<ISuiteListener> suiteListenersReversed =
247-
ListenerOrderDeterminer.reversedOrder(
248-
listeners.values(), this.configuration.getListenerComparator());
249-
for (ISuiteListener sl : suiteListenersReversed) {
250-
sl.onFinish(this);
251-
}
245+
ListenerOrderDeterminer.reversedOrder(
246+
listeners.values(), this.configuration.getListenerComparator())
247+
.stream()
248+
.filter(ITestNGListener::isEnabled)
249+
.forEach(it -> it.onFinish(this));
252250
}
253251
}
254252

testng-core/src/main/java/org/testng/TestNG.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,28 +1112,26 @@ protected List<ISuite> runSuites() {
11121112
private void runSuiteAlterationListeners() {
11131113
Collection<IAlterSuiteListener> original =
11141114
sort(m_alterSuiteListeners.values(), m_configuration.getListenerComparator());
1115-
for (IAlterSuiteListener l : original) {
1116-
l.alter(m_suites);
1117-
}
1115+
original.stream().filter(ITestNGListener::isEnabled).forEach(it -> it.alter(m_suites));
11181116
}
11191117

11201118
private void runExecutionListeners(boolean start) {
11211119
List<IExecutionListener> executionListeners =
11221120
ListenerOrderDeterminer.order(
11231121
m_configuration.getExecutionListeners(), m_configuration.getListenerComparator());
11241122
if (start) {
1125-
for (IExecutionListener l : executionListeners) {
1126-
l.onExecutionStart();
1127-
}
1123+
executionListeners.stream()
1124+
.filter(ITestNGListener::isEnabled)
1125+
.forEach(IExecutionListener::onExecutionStart);
11281126
// Invoke our exit code listener after all the user's listeners have run.
11291127
exitCodeListener.onExecutionStart();
11301128
} else {
11311129
List<IExecutionListener> executionListenersReversed =
11321130
ListenerOrderDeterminer.reversedOrder(
11331131
m_configuration.getExecutionListeners(), m_configuration.getListenerComparator());
1134-
for (IExecutionListener l : executionListenersReversed) {
1135-
l.onExecutionFinish();
1136-
}
1132+
executionListenersReversed.stream()
1133+
.filter(ITestNGListener::isEnabled)
1134+
.forEach(IExecutionListener::onExecutionFinish);
11371135
// Invoke our exit code listener after all the user's listeners have run.
11381136
exitCodeListener.onExecutionFinish();
11391137
}
@@ -1152,6 +1150,9 @@ private void generateReports(List<ISuite> suiteRunners) {
11521150
// whatever changes were done by a user's reporting listener
11531151
reporters.add(exitCodeListener);
11541152
for (IReporter reporter : reporters) {
1153+
if (!reporter.isEnabled()) {
1154+
continue;
1155+
}
11551156
try {
11561157
long start = System.currentTimeMillis();
11571158
reporter.generateReport(m_suites, suiteRunners, m_outputDir);

testng-core/src/main/java/org/testng/TestRunner.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,9 @@ private ITestNGMethod[] intercept(ITestNGMethod[] methods) {
745745
List<IMethodInterceptor> original =
746746
sort(m_methodInterceptors, m_configuration.getListenerComparator());
747747
for (IMethodInterceptor m_methodInterceptor : original) {
748-
methodInstances = m_methodInterceptor.intercept(methodInstances, this);
748+
if (m_methodInterceptor.isEnabled()) {
749+
methodInstances = m_methodInterceptor.intercept(methodInstances, this);
750+
}
749751
}
750752

751753
List<ITestNGMethod> result = MethodHelper.methodInstancesToMethods(methodInstances);
@@ -853,19 +855,18 @@ private void logStart() {
853855
*/
854856
private void fireEvent(boolean isStart) {
855857
if (isStart) {
856-
for (ITestListener itl :
857-
ListenerOrderDeterminer.order(m_testListeners, m_configuration.getListenerComparator())) {
858-
itl.onStart(this);
859-
}
858+
ListenerOrderDeterminer.order(m_testListeners, m_configuration.getListenerComparator())
859+
.stream()
860+
.filter(ITestNGListener::isEnabled)
861+
.forEach(it -> it.onStart(this));
860862
this.exitCodeListener.onStart(this);
861863

862864
} else {
863-
List<ITestListener> testListenersReversed =
864-
ListenerOrderDeterminer.reversedOrder(
865-
m_testListeners, m_configuration.getListenerComparator());
866-
for (ITestListener itl : testListenersReversed) {
867-
itl.onFinish(this);
868-
}
865+
ListenerOrderDeterminer.reversedOrder(
866+
m_testListeners, m_configuration.getListenerComparator())
867+
.stream()
868+
.filter(ITestNGListener::isEnabled)
869+
.forEach(it -> it.onFinish(this));
869870
this.exitCodeListener.onFinish(this);
870871
}
871872
if (!isStart) {
@@ -1102,7 +1103,9 @@ public void addListener(ITestNGListener listener) {
11021103
if (listener instanceof IExecutionListener) {
11031104
IExecutionListener iel = (IExecutionListener) listener;
11041105
if (m_configuration.addExecutionListenerIfAbsent(iel)) {
1105-
iel.onExecutionStart();
1106+
if (iel.isEnabled()) {
1107+
iel.onExecutionStart();
1108+
}
11061109
}
11071110
}
11081111
if (listener instanceof IDataProviderListener) {

testng-core/src/main/java/org/testng/internal/DynamicGraph.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.concurrent.ConcurrentHashMap;
1010
import org.testng.IDynamicGraph;
1111
import org.testng.IExecutionVisualiser;
12+
import org.testng.ITestNGListener;
1213
import org.testng.collections.Lists;
1314
import org.testng.collections.Maps;
1415
import org.testng.collections.Sets;
@@ -142,7 +143,9 @@ public void setStatus(T node, Status status) {
142143
throw new IllegalArgumentException("Unsupported status: " + status);
143144
}
144145

145-
this.visualisers.forEach(visualiser -> visualiser.consumeDotDefinition(toDot()));
146+
this.visualisers.stream()
147+
.filter(ITestNGListener::isEnabled)
148+
.forEach(visualiser -> visualiser.consumeDotDefinition(toDot()));
146149
}
147150

148151
/** @return the number of nodes in this graph. */

testng-core/src/main/java/org/testng/internal/Parameters.java

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
import java.util.*;
99
import org.testng.DataProviderHolder;
1010
import org.testng.IDataProviderInterceptor;
11-
import org.testng.IDataProviderListener;
1211
import org.testng.IDataProviderMethod;
1312
import org.testng.IRetryDataProvider;
1413
import org.testng.ITestClass;
1514
import org.testng.ITestContext;
15+
import org.testng.ITestNGListener;
1616
import org.testng.ITestNGMethod;
1717
import org.testng.ITestObjectFactory;
1818
import org.testng.ITestResult;
@@ -799,10 +799,12 @@ public static ParameterHolder handleParameters(
799799
RuntimeException thrownException;
800800
do {
801801

802-
for (IDataProviderListener dataProviderListener : holder.getListeners()) {
803-
dataProviderListener.beforeDataProviderExecution(
804-
dataProviderMethod, testMethod, methodParams.context);
805-
}
802+
holder.getListeners().stream()
803+
.filter(ITestNGListener::isEnabled)
804+
.forEach(
805+
it ->
806+
it.beforeDataProviderExecution(
807+
dataProviderMethod, testMethod, methodParams.context));
806808

807809
try {
808810
initParams =
@@ -817,9 +819,9 @@ public static ParameterHolder handleParameters(
817819
shouldRetry = false;
818820
thrownException = null;
819821
} catch (RuntimeException e) {
820-
for (IDataProviderListener each : holder.getListeners()) {
821-
each.onDataProviderFailure(testMethod, methodParams.context, e);
822-
}
822+
holder.getListeners().stream()
823+
.filter(ITestNGListener::isEnabled)
824+
.forEach(it -> it.onDataProviderFailure(testMethod, methodParams.context, e));
823825
if (shouldRetry) {
824826
shouldRetry = retry.retry(dataProviderMethod);
825827
thrownException = e;
@@ -840,10 +842,12 @@ public static ParameterHolder handleParameters(
840842
throw thrownException;
841843
}
842844

843-
for (IDataProviderListener dataProviderListener : holder.getListeners()) {
844-
dataProviderListener.afterDataProviderExecution(
845-
dataProviderMethod, testMethod, methodParams.context);
846-
}
845+
holder.getListeners().stream()
846+
.filter(ITestNGListener::isEnabled)
847+
.forEach(
848+
it ->
849+
it.afterDataProviderExecution(
850+
dataProviderMethod, testMethod, methodParams.context));
847851

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

856860
testMethod.setMoreInvocationChecker(filteredParameters::hasNext);
857861
for (IDataProviderInterceptor interceptor : holder.getInterceptors()) {
858-
filteredParameters =
859-
interceptor.intercept(
860-
filteredParameters, dataProviderMethod, testMethod, methodParams.context);
862+
if (interceptor.isEnabled()) {
863+
filteredParameters =
864+
interceptor.intercept(
865+
filteredParameters, dataProviderMethod, testMethod, methodParams.context);
866+
}
861867
}
862868

863869
if (dataProviderMethod instanceof DataProviderMethodRemovable) {

testng-core/src/main/java/org/testng/internal/TestListenerHelper.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ private static void ignoreInternalGradleException(Exception e) {
9999
*/
100100
public static void runTestListeners(ITestResult tr, List<ITestListener> listeners) {
101101
for (ITestListener itl : listeners) {
102+
if (!itl.isEnabled()) {
103+
continue;
104+
}
102105
switch (tr.getStatus()) {
103106
case ITestResult.SKIP:
104107
itl.onTestSkipped(tr);

testng-core/src/main/java/org/testng/internal/annotations/JDK15AnnotationFinder.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,20 +166,32 @@ private void transform(
166166
if (m_transformer instanceof org.testng.internal.annotations.IAnnotationTransformer) {
167167
org.testng.internal.annotations.IAnnotationTransformer transformer =
168168
(org.testng.internal.annotations.IAnnotationTransformer) m_transformer;
169-
transformer.transform(
170-
(ITestAnnotation) a, testClass, testConstructor, testMethod, whichClass);
169+
if (transformer.isEnabled()) {
170+
transformer.transform(
171+
(ITestAnnotation) a, testClass, testConstructor, testMethod, whichClass);
172+
}
171173
} else {
172-
m_transformer.transform((ITestAnnotation) a, testClass, testConstructor, testMethod);
174+
if (m_transformer.isEnabled()) {
175+
m_transformer.transform((ITestAnnotation) a, testClass, testConstructor, testMethod);
176+
}
173177
}
174178
} else if (a instanceof IConfigurationAnnotation) {
175179
IConfigurationAnnotation configuration = (IConfigurationAnnotation) a;
176-
m_transformer.transform(configuration, testClass, testConstructor, testMethod);
180+
if (m_transformer.isEnabled()) {
181+
m_transformer.transform(configuration, testClass, testConstructor, testMethod);
182+
}
177183
} else if (a instanceof IDataProviderAnnotation) {
178-
m_transformer.transform((IDataProviderAnnotation) a, testMethod);
184+
if (m_transformer.isEnabled()) {
185+
m_transformer.transform((IDataProviderAnnotation) a, testMethod);
186+
}
179187
} else if (a instanceof IFactoryAnnotation) {
180-
m_transformer.transform((IFactoryAnnotation) a, testMethod);
188+
if (m_transformer.isEnabled()) {
189+
m_transformer.transform((IFactoryAnnotation) a, testMethod);
190+
}
181191
} else if (a instanceof IListenersAnnotation) {
182-
m_transformer.transform((IListenersAnnotation) a, testClass);
192+
if (m_transformer.isEnabled()) {
193+
m_transformer.transform((IListenersAnnotation) a, testClass);
194+
}
183195
}
184196
}
185197

testng-core/src/main/java/org/testng/internal/invokers/InvokedMethodListenerInvoker.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ public InvokedMethodListenerInvoker(
5151
*/
5252
public void invokeListener(
5353
IInvokedMethodListener listenerInstance, IInvokedMethod invokedMethod) {
54+
if (!listenerInstance.isEnabled()) {
55+
return;
56+
}
5457
if (this.m_listenerMethod == BEFORE_INVOCATION) {
5558
listenerInstance.beforeInvocation(invokedMethod, m_testResult);
5659
listenerInstance.beforeInvocation(invokedMethod, m_testResult, m_testContext);

testng-core/src/main/java/org/testng/internal/invokers/TestMethodWorker.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.testng.IMethodInstance;
1414
import org.testng.ITestClass;
1515
import org.testng.ITestContext;
16+
import org.testng.ITestNGListener;
1617
import org.testng.ITestNGMethod;
1718
import org.testng.ITestResult;
1819
import org.testng.collections.Lists;
@@ -167,11 +168,9 @@ protected void invokeBeforeClassMethods(ITestClass testClass, IMethodInstance mi
167168
Object instance = mi.getInstance();
168169
if (!instances.contains(instance)) {
169170
instances.add(instance);
170-
List<IClassListener> original =
171-
sort(m_listeners, m_configInvoker.getConfiguration().getListenerComparator());
172-
for (IClassListener listener : original) {
173-
listener.onBeforeClass(testClass);
174-
}
171+
sort(m_listeners, m_configInvoker.getConfiguration().getListenerComparator()).stream()
172+
.filter(ITestNGListener::isEnabled)
173+
.forEach(it -> it.onBeforeClass(testClass));
175174
ConfigMethodArguments attributes =
176175
new Builder()
177176
.forTestClass(testClass)
@@ -235,11 +234,9 @@ private void invokeAfterClassConfigurations(ITestClass testClass, List<Object> i
235234
}
236235

237236
private void invokeListenersOnAfterClass(ITestClass testClass, List<IClassListener> listeners) {
238-
List<IClassListener> original =
239-
sort(listeners, m_configInvoker.getConfiguration().getListenerComparator());
240-
for (IClassListener listener : original) {
241-
listener.onAfterClass(testClass);
242-
}
237+
sort(listeners, m_configInvoker.getConfiguration().getListenerComparator()).stream()
238+
.filter(ITestNGListener::isEnabled)
239+
.forEach(it -> it.onAfterClass(testClass));
243240
}
244241

245242
protected int indexOf(ITestNGMethod tm, ITestNGMethod[] allTestMethods) {

testng-core/src/test/java/test/listeners/ListenersTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.testng.internal.ExitCode;
1919
import org.testng.xml.XmlSuite;
2020
import test.SimpleBaseTest;
21+
import test.listeners.issue2381.SampleGlobalListener;
2122
import test.listeners.issue2638.DummyInvokedMethodListener;
2223
import test.listeners.issue2638.TestClassASample;
2324
import test.listeners.issue2638.TestClassBSample;
@@ -521,6 +522,15 @@ public void testSkipStatusInBeforeAndAfterConfigurationMethod(
521522
assertThat(listener.getLogs()).containsExactlyElementsOf(expected);
522523
}
523524

525+
@Test(description = "GITHUB-2381")
526+
public void ensureListenersCanBeDisabled() {
527+
TestNG testng = create(test.listeners.issue2381.TestClassSample.class);
528+
SampleGlobalListener listener = new SampleGlobalListener();
529+
testng.addListener(listener);
530+
testng.run();
531+
assertThat(listener.getLogs()).isEmpty();
532+
}
533+
524534
private void setupTest(boolean addExplicitListener) {
525535
TestNG testng = new TestNG();
526536
XmlSuite xmlSuite = createXmlSuite("Xml_Suite");

0 commit comments

Comments
 (0)