Skip to content

Commit ca7a3a2

Browse files
committed
Ensure All tests run all the time
Closes #2841
1 parent a5b8508 commit ca7a3a2

17 files changed

+85
-67
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,10 @@ private void privateRun() {
347347
// -- cbeust
348348
invoker = tr.getInvoker();
349349

350+
// Add back the configuration listeners that may have gotten altered after
351+
// our suite level listeners were invoked.
352+
this.configuration.getConfigurationListeners().forEach(tr::addConfigurationListener);
353+
350354
for (ITestNGMethod m : tr.getBeforeSuiteMethods()) {
351355
beforeSuiteMethods.put(m.getConstructorOrMethod().getMethod(), m);
352356
}

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import java.util.Date;
1111
import java.util.List;
1212
import java.util.Map;
13-
import java.util.Optional;
1413
import java.util.Set;
1514
import java.util.concurrent.BlockingQueue;
1615
import java.util.concurrent.LinkedBlockingQueue;
@@ -1160,14 +1159,12 @@ public void setVerbose(int n) {
11601159
// TODO: This method needs to be removed and we need to be leveraging addListener().
11611160
// Investigate and fix this.
11621161
void addTestListener(ITestListener listener) {
1163-
Optional<ITestListener> found =
1162+
boolean found =
11641163
m_testListeners.stream()
1165-
.filter(iTestListener -> iTestListener.getClass().equals(listener.getClass()))
1166-
.findAny();
1167-
if (found.isPresent()) {
1168-
return;
1164+
.anyMatch(iTestListener -> iTestListener.getClass().equals(listener.getClass()));
1165+
if (!found) {
1166+
m_testListeners.add(listener);
11691167
}
1170-
m_testListeners.add(listener);
11711168
}
11721169

11731170
public void addListener(ITestNGListener listener) {
@@ -1214,7 +1211,11 @@ public void addListener(ITestNGListener listener) {
12141211
}
12151212

12161213
void addConfigurationListener(IConfigurationListener icl) {
1217-
m_configurationListeners.add(icl);
1214+
boolean alreadyAdded =
1215+
m_configurationListeners.stream().anyMatch(each -> each.getClass().equals(icl.getClass()));
1216+
if (!alreadyAdded) {
1217+
m_configurationListeners.add(icl);
1218+
}
12181219
}
12191220

12201221
private void dumpInvokedMethods() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public boolean equals(Object o) {
2323
if (this == o) return true;
2424
if (o == null || getClass() != o.getClass()) return false;
2525
ClassBasedWrapper<?> wrapper = (ClassBasedWrapper<?>) o;
26-
return object.getClass().equals(wrapper.getClass());
26+
return object.getClass().equals(wrapper.object.getClass());
2727
}
2828

2929
@Override

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class MethodHelper {
4545
* @param finder annotation finder
4646
* @param unique true for unique methods, false otherwise
4747
* @param outExcludedMethods - A List of excluded {@link ITestNGMethod} methods.
48-
* @return list of ordered methods
48+
* @return an array of ordered methods
4949
*/
5050
public static ITestNGMethod[] collectAndOrderMethods(
5151
List<ITestNGMethod> methods,
@@ -82,7 +82,7 @@ public static ITestNGMethod[] collectAndOrderMethods(
8282
*
8383
* @param m TestNG method
8484
* @param methods list of methods to search for depended upon methods
85-
* @return list of methods that match the criteria
85+
* @return an array of methods that match the criteria
8686
*/
8787
protected static ITestNGMethod[] findDependedUponMethods(
8888
ITestNGMethod m, List<ITestNGMethod> methods) {
@@ -95,18 +95,14 @@ protected static ITestNGMethod[] findDependedUponMethods(
9595
*
9696
* @param m TestNG method
9797
* @param incoming list of methods to search for depended upon methods
98-
* @return list of methods that match the criteria
98+
* @return an array of methods that match the criteria
9999
*/
100100
public static ITestNGMethod[] findDependedUponMethods(ITestNGMethod m, ITestNGMethod[] incoming) {
101101
ITestNGMethod[] methods =
102102
Arrays.stream(incoming)
103103
.filter(each -> !each.equals(m))
104104
.filter(each -> Objects.isNull(each.getRealClass().getEnclosingClass()))
105105
.toArray(ITestNGMethod[]::new);
106-
if (methods.length == 0) {
107-
return new ITestNGMethod[] {};
108-
}
109-
110106
String canonicalMethodName = calculateMethodCanonicalName(m);
111107

112108
List<ITestNGMethod> vResult = Lists.newArrayList();

testng-core/src/test/groovy/test/groovy/SpockSample.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ class SpockSample extends Specification {
1414
then:
1515
stack.size() == 1
1616
}
17-
}
17+
}

testng-core/src/test/java/test/InvokedMethodNameListener.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
5858
@Override
5959
public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
6060
List<String> methodNames =
61-
mapping.computeIfAbsent(testResult.getMethod().getRealClass(), k -> Lists.newArrayList());
61+
mapping.computeIfAbsent(
62+
testResult.getMethod().getRealClass(),
63+
k -> Collections.synchronizedList(Lists.newArrayList()));
6264
methodNames.add(method.getTestMethod().getMethodName());
6365
String name = getName(testResult);
6466
switch (testResult.getStatus()) {

testng-core/src/test/java/test/dataprovider/DataProviderTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,12 @@ public void testDataProviderCanBeRetriedViaAnnotationTransformer() {
7878

7979
@Test(description = "GITHUB-2819")
8080
public void testDataProviderRetryInstancesAreUniqueForEachDataDrivenTest() {
81+
SimpleRetry.clearObjectIds();
8182
TestNG testng = create(TestClassWithMultipleRetryImplSample.class);
8283
DataProviderListenerForRetryAwareTests listener = new DataProviderListenerForRetryAwareTests();
8384
testng.addListener(listener);
8485
testng.run();
85-
assertThat(SimpleRetry.getHashCodes()).hasSize(2);
86+
assertThat(SimpleRetry.getObjectIds()).hasSize(2);
8687
// Without retrying itself we would have already invoked the listener once.
8788
assertThat(listener.getBeforeInvocations()).isEqualTo(6);
8889
assertThat(listener.getFailureInvocations()).isEqualTo(4);

testng-core/src/test/java/test/dataprovider/issue2819/SimpleRetry.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,24 @@
33
import java.util.Collections;
44
import java.util.HashSet;
55
import java.util.Set;
6+
import java.util.UUID;
67
import org.testng.IDataProviderMethod;
78
import org.testng.IRetryDataProvider;
89

910
public class SimpleRetry implements IRetryDataProvider {
1011

11-
private static final Set<Integer> hashCodes = new HashSet<>();
12+
private static final Set<String> objectIds = new HashSet<>();
1213

13-
public static Set<Integer> getHashCodes() {
14-
return Collections.unmodifiableSet(hashCodes);
14+
public static Set<String> getObjectIds() {
15+
return Collections.unmodifiableSet(objectIds);
16+
}
17+
18+
public static void clearObjectIds() {
19+
objectIds.clear();
1520
}
1621

1722
public SimpleRetry() {
18-
hashCodes.add(hashCode());
23+
objectIds.add(UUID.randomUUID().toString());
1924
}
2025

2126
private int counter = 0;

testng-core/src/test/java/test/dependent/DependentTest.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,8 @@ public void ensureDependsOnMethodsHonoursRegexPatternsAcrossClassesErrorConditio
6464
description = "GITHUB-141",
6565
expectedExceptions = TestNGException.class,
6666
expectedExceptionsMessageRegExp =
67-
"\nMethod \"test.dependent.issue141.ErrorScenarioNestedSample.a\\(\\)\" "
68-
+ "depends on nonexistent "
69-
+ "method \"test.dependent.issue141.ErrorScenarioNestedSample\\$InnerTestClass"
70-
+ ".rambo.*")
67+
"\ntest.dependent.issue141.ErrorScenarioNestedSample.a\\(\\) "
68+
+ "depends on nonexistent method .*")
7169
public void ensureDependsOnMethodsHonoursRegexPatternsNestedClassesErrorCondition() {
7270
TestNG testng = create(ErrorScenarioNestedSample.class);
7371
MethodNameCollector listener = new MethodNameCollector();
@@ -101,9 +99,7 @@ public void ensureDependsOnMethodsHonoursRegexPatternsDuplicateMatches() {
10199
@Test(
102100
description = "GITHUB-141",
103101
expectedExceptions = TestNGException.class,
104-
expectedExceptionsMessageRegExp =
105-
"\nMethod \"test.dependent.issue141.NestedTestClassSample\\$FirstSample.randomTest\\(\\)\" "
106-
+ "depends on nonexistent method .*")
102+
expectedExceptionsMessageRegExp = "\n.* depends on nonexistent method .*")
107103
public void ensureDependsOnMethodsHonoursRegexPatternsDuplicateMatchesNestedClasses() {
108104
TestNG testng = create(NestedTestClassSample.class);
109105
MethodNameCollector listener = new MethodNameCollector();
@@ -117,7 +113,7 @@ public void ensureDependsOnMethodsHonoursRegexPatternsDuplicateMatchesNestedClas
117113
description = "GITHUB-141",
118114
expectedExceptions = TestNGException.class,
119115
expectedExceptionsMessageRegExp =
120-
"\nMethod \"test.dependent.issue141.NestedTestClassSample2.randomTest\\(\\)\" depends on "
116+
"\ntest.dependent.issue141.NestedTestClassSample2.randomTest\\(\\) depends on "
121117
+ "nonexistent method .*")
122118
public void ensureDependsOnMethodsHonourRegexPatternsNestedClasses() {
123119
TestNG testng = create(NestedTestClassSample2.class);

testng-core/src/test/java/test/listeners/github1130/GitHub1130Test.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import static org.assertj.core.api.Assertions.assertThat;
44

5-
import java.util.ArrayList;
65
import org.testng.ITestNGListener;
76
import org.testng.TestListenerAdapter;
87
import org.testng.TestNG;
@@ -22,19 +21,20 @@ public void classListenerShouldBeOnlyInstantiatedOnce() {
2221
}
2322

2423
private void checkGithub1130(TestNG tng) {
25-
MyListener.count = 0;
26-
MyListener.beforeSuiteCount = new ArrayList<>();
27-
MyListener.beforeClassCount = new ArrayList<>();
2824
TestListenerAdapter adapter = new TestListenerAdapter();
2925
tng.addListener((ITestNGListener) adapter);
3026
tng.run();
3127
assertThat(adapter.getFailedTests()).isEmpty();
3228
assertThat(adapter.getSkippedTests()).isEmpty();
33-
assertThat(MyListener.beforeSuiteCount.size()).isEqualTo(1);
34-
assertThat(MyListener.beforeClassCount.size()).isEqualTo(2);
35-
assertThat(MyListener.beforeSuiteCount.get(0))
36-
.isEqualTo(MyListener.beforeClassCount.get(0))
37-
.isEqualTo(MyListener.beforeClassCount.get(1));
38-
assertThat(MyListener.count).isEqualTo(1);
29+
// We cannot prevent TestNG from instantiating a listener multiple times
30+
// because TestNG can throw away listener instances if it finds them already registered
31+
// So the assertion should basically be able to check that ONLY 1 instance of the listener
32+
// is being used, even though TestNG created multiple instances of it.
33+
assertThat(MyListener.instance).isNotNull();
34+
assertThat(MyListener.instance.beforeSuiteCount.size()).isEqualTo(1);
35+
assertThat(MyListener.instance.beforeClassCount.size()).isEqualTo(2);
36+
assertThat(MyListener.instance.beforeSuiteCount.get(0))
37+
.isEqualTo(MyListener.instance.beforeClassCount.get(0))
38+
.isEqualTo(MyListener.instance.beforeClassCount.get(1));
3939
}
4040
}

testng-core/src/test/java/test/listeners/github1130/MyListener.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111

1212
public class MyListener implements ISuiteListener, IClassListener {
1313

14-
public static int count = 0;
15-
public static List<String> beforeSuiteCount = new ArrayList<>();
16-
public static List<String> beforeClassCount = new ArrayList<>();
14+
public static MyListener instance;
15+
public List<String> beforeSuiteCount = new ArrayList<>();
16+
public List<String> beforeClassCount = new ArrayList<>();
1717

1818
public MyListener() {
19-
count++;
19+
if (instance == null) {
20+
instance = this;
21+
}
2022
}
2123

2224
public void onStart(ISuite suite) {

testng-core/src/test/java/test/listeners/github1296/GitHub1296Test.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static org.assertj.core.api.Assertions.assertThat;
44
import static org.assertj.core.api.Assertions.entry;
5+
import static test.listeners.github1296.MyConfigurationListener.getCalls;
56

67
import org.testng.TestNG;
78
import org.testng.annotations.Test;
@@ -12,7 +13,7 @@ public class GitHub1296Test extends SimpleBaseTest {
1213

1314
@Test(description = "https://github.com/cbeust/testng/issues/1296")
1415
public void test_number_of_call_of_configuration_listener() {
15-
MyConfigurationListener.CALLS.clear();
16+
MyConfigurationListener.clearCalls();
1617
XmlSuite suite = createXmlSuite("Tests");
1718
createXmlTest(suite, "Test version", MyTest.class);
1819
createXmlTest(suite, "Test version 2", MyTest.class);
@@ -21,7 +22,7 @@ public void test_number_of_call_of_configuration_listener() {
2122

2223
tng.run();
2324

24-
assertThat(MyConfigurationListener.CALLS)
25+
assertThat(getCalls())
2526
.hasSize(3)
2627
.containsOnly(
2728
entry("Test version", 2), entry("Test version 2", 2), entry("Test version 3", 2));

testng-core/src/test/java/test/listeners/github1296/MyConfigurationListener.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
package test.listeners.github1296;
22

3-
import java.util.HashMap;
43
import java.util.Map;
4+
import java.util.Map.Entry;
5+
import java.util.concurrent.ConcurrentHashMap;
6+
import java.util.concurrent.atomic.AtomicInteger;
7+
import java.util.stream.Collectors;
58
import org.testng.IConfigurationListener;
69
import org.testng.ITestResult;
710

811
public class MyConfigurationListener implements IConfigurationListener {
912

10-
public static final Map<String, Integer> CALLS = new HashMap<>();
13+
private static final Map<String, AtomicInteger> CALLS = new ConcurrentHashMap<>();
14+
15+
public static void clearCalls() {
16+
CALLS.clear();
17+
}
18+
19+
public static Map<String, Integer> getCalls() {
20+
return CALLS.entrySet().stream()
21+
.collect(Collectors.toMap(Entry::getKey, each -> each.getValue().get()));
22+
}
1123

1224
@Override
1325
public void onConfigurationSuccess(ITestResult itr) {
1426
String xmlTestName = itr.getTestContext().getCurrentXmlTest().getName();
15-
Integer count = CALLS.get(xmlTestName);
16-
if (count == null) {
17-
count = 0;
18-
}
19-
count++;
20-
CALLS.put(xmlTestName, count);
27+
CALLS.computeIfAbsent(xmlTestName, k -> new AtomicInteger()).incrementAndGet();
2128
}
2229

2330
@Override

testng-core/src/test/java/test/reports/EmailableReporterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private void runTestViaMainMethod(String clazzName, String jvm) {
7575
if (jvm != null) {
7676
System.setProperty(jvm, filename);
7777
}
78-
TestNG.main(args);
78+
TestNG.privateMain(args, null);
7979
} catch (SecurityException t) {
8080
// Gobble Security exception
8181
} finally {

testng-core/src/test/java/test/yaml/YamlTest.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package test.yaml;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.junit.jupiter.api.Assertions.assertFalse;
5-
import static org.junit.jupiter.api.Assertions.assertTrue;
64

75
import java.io.File;
86
import java.io.FileInputStream;
@@ -38,10 +36,9 @@ public Object[][] dp() {
3836
"Validate that the YamlParser accepts yaml files with a .yaml or a .yml file extension, but not other file types.")
3937
public void accept() {
4038
YamlParser yamlParser = new YamlParser();
41-
42-
assertTrue(yamlParser.accept("TestSuite.yml"));
43-
assertTrue(yamlParser.accept("TestSuite.yaml"));
44-
assertFalse(yamlParser.accept("TestSuite.xml"));
39+
assertThat(yamlParser.accept("TestSuite.yml")).isTrue();
40+
assertThat(yamlParser.accept("TestSuite.yaml")).isTrue();
41+
assertThat(yamlParser.accept("TestSuite.xml")).isFalse();
4542
}
4643

4744
@Test(dataProvider = "dp")

testng-core/testng-core-build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ dependencies {
3737
implementation(projects.testngReflectionUtils)
3838
implementation(projects.testngRunnerApi)
3939
implementation("org.webjars:jquery:_")
40-
4140
testImplementation(projects.testngAsserts)
42-
testImplementation("org.codehaus.groovy:groovy-all:_")
41+
testImplementation("org.codehaus.groovy:groovy-all:_") {
42+
exclude("org.testng", "testng")
43+
}
4344
testImplementation("org.spockframework:spock-core:_")
4445
testImplementation("org.apache-extras.beanshell:bsh:_")
4546
testImplementation("org.mockito:mockito-core:_")
@@ -64,7 +65,6 @@ tasks.test {
6465
maxParallelForks = Runtime.getRuntime().availableProcessors().div(2)
6566
(testFramework.options as TestNGOptions).apply {
6667
suites("src/test/resources/testng.xml")
67-
listeners.add("org.testng.reporters.FailedInformationOnConsoleReporter")
6868
maxHeapSize = "1500m"
6969
}
7070
}

versions.properties

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ version.org.assertj..assertj-core=3.22.0
104104
## # available=3.23.0
105105
## # available=3.23.1
106106

107-
version.org.codehaus.groovy..groovy-all=3.0.10
107+
## DONOT alter the version of groovy here because we need the compatible
108+
## version with what spock needs
109+
version.org.codehaus.groovy..groovy-all=2.5.4
108110
## # available=3.0.11
109111
## # available=3.0.12
110112
## # available=3.0.13
@@ -127,7 +129,11 @@ version.org.ops4j.pax.exam..pax-exam-testng=4.13.5
127129

128130
version.org.ops4j.pax.url..pax-url-aether=2.6.12
129131

130-
version.org.spockframework..spock-core=2.1-groovy-3.0
132+
## DONOT upgrade the version to the 2.x series because spock 2.x series
133+
## starts expecting adherance the JUnit5 engine and we are NOT
134+
## planning to support running JUnit5 tests in TestNG and so we don't have
135+
## JUnit5 compliant runner
136+
version.org.spockframework..spock-core=1.3-groovy-2.5
131137
## # available=2.1-M1-groovy-2.5
132138
## # available=2.1-M1-groovy-3.0
133139
## # available=2.1-M2-groovy-2.5

0 commit comments

Comments
 (0)