Skip to content

Commit f981dec

Browse files
ghalepshevche
authored andcommitted
Fix issue with test event not being generated
Signed-off-by: Pavlo Shevchenko <[email protected]>
1 parent 899dc9a commit f981dec

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

plugin/src/main/java/org/gradle/testretry/internal/executer/RetryTestResultProcessor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,15 @@ private void failure(Object testId) {
261261

262262
private boolean lastRun() {
263263
return currentRoundFailedTests.isEmpty()
264+
|| hasNonRetriedTests()
264265
|| lastRetry
265266
|| currentRoundFailedTestsExceedsMaxFailures();
266267
}
267268

269+
private boolean hasNonRetriedTests() {
270+
return !cleanedUpFailedTestsOfPreviousRound().isEmpty();
271+
}
272+
268273
private boolean currentRoundFailedTestsExceedsMaxFailures() {
269274
return maxFailures > 0 && currentRoundFailedTests.size() >= maxFailures;
270275
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package org.gradle.testretry
2+
3+
import org.gradle.testkit.runner.TaskOutcome
4+
import org.gradle.util.GradleVersion
5+
import org.intellij.lang.annotations.Language
6+
import spock.lang.Issue
7+
8+
class TestLifecycleEventFuncTest extends AbstractPluginFuncTest {
9+
@Override
10+
String getLanguagePlugin() {
11+
return 'java'
12+
}
13+
14+
@Override
15+
protected String buildConfiguration() {
16+
return """
17+
${CAPTURE_EVENTS}
18+
19+
dependencies {
20+
testImplementation("org.testng:testng:7.7.1")
21+
testRuntimeOnly("org.junit.support:testng-engine:1.0.4")
22+
}
23+
24+
java {
25+
toolchain {
26+
languageVersion.set(JavaLanguageVersion.of(11))
27+
}
28+
}
29+
30+
tasks.named("test").configure {
31+
retry {
32+
maxRetries = 3
33+
}
34+
35+
useJUnitPlatform {
36+
includeEngines("testng")
37+
excludeEngines("junit-jupiter", "junit-vintage")
38+
}
39+
}
40+
"""
41+
}
42+
43+
@Issue("https://github.com/gradle/gradle/issues/29633")
44+
def "all internal test events are generated when error occurs while initializing test"() {
45+
writeJavaTestSource("""
46+
package org.gradle.test;
47+
48+
import org.testng.Assert;
49+
import org.testng.annotations.*;
50+
51+
public class SomeTest {
52+
@Test
53+
public void test_demo_1() {
54+
Assert.assertTrue(true, "Test pass");
55+
}
56+
}
57+
""")
58+
59+
// test_demo_2 will initialize successfully on the first test execution, and will fail.
60+
// On the retry, it will fail to initialize because it depends on SomeTest.test_demo_1,
61+
// which will not be included in the execution (because it passed on the first execution),
62+
// causing an error and no retry.
63+
writeJavaTestSource("""
64+
package org.gradle.test;
65+
66+
import org.testng.Assert;
67+
import org.testng.annotations.*;
68+
69+
public class SomeTest2 {
70+
@Test
71+
public void test_demo_1() {
72+
Assert.assertTrue(true, "Test pass");
73+
}
74+
75+
@Test(dependsOnMethods = {"test_demo_1"})
76+
public void test_demo_2() {
77+
Assert.assertTrue(false, "Test fail");
78+
}
79+
}
80+
""")
81+
82+
when:
83+
def result = gradleRunner(GradleVersion.current() as String, "test").buildAndFail()
84+
85+
then:
86+
result.output.contains("SomeTest2 > test_demo_2 FAILED")
87+
result.output.contains("The following test methods could not be retried, which is unexpected.")
88+
89+
and:
90+
result.task(":checkEvents").outcome == TaskOutcome.SUCCESS
91+
}
92+
93+
@Language("groovy")
94+
private static final String CAPTURE_EVENTS = """
95+
import org.gradle.api.tasks.testing.TestOutputEvent
96+
import org.gradle.internal.event.ListenerManager
97+
import org.gradle.api.internal.tasks.testing.results.TestListenerInternal
98+
import org.gradle.api.internal.tasks.testing.report.TestResult
99+
import org.gradle.api.internal.tasks.testing.TestDescriptorInternal
100+
import org.gradle.api.internal.tasks.testing.TestStartEvent
101+
import org.gradle.api.internal.tasks.testing.TestCompleteEvent
102+
103+
def capture = new EventCapture()
104+
def checkEvents = tasks.register("checkEvents") {
105+
doLast {
106+
capture.events.each { testDescriptor, eventList ->
107+
if (!eventList.contains(Event.STARTED)) {
108+
throw new IllegalStateException("Test \$testDescriptor did not register a start event")
109+
}
110+
if (!eventList.contains(Event.COMPLETED)) {
111+
throw new IllegalStateException("Test \$testDescriptor did not register a complete event")
112+
}
113+
}
114+
}
115+
}
116+
117+
tasks.named("test").configure {
118+
getServices().get(ListenerManager).addListener(capture)
119+
finalizedBy checkEvents
120+
}
121+
122+
enum Event {
123+
STARTED, COMPLETED, OUTPUT
124+
}
125+
126+
class EventCapture implements TestListenerInternal {
127+
def events = [:]
128+
129+
void started(TestDescriptorInternal testDescriptor, TestStartEvent startEvent) {
130+
registerEvent(testDescriptor, Event.STARTED)
131+
}
132+
133+
@Override
134+
void completed(TestDescriptorInternal testDescriptor ,org.gradle.api.tasks.testing.TestResult testResult ,TestCompleteEvent completeEvent) {
135+
registerEvent(testDescriptor, Event.COMPLETED)
136+
}
137+
138+
void output(TestDescriptorInternal testDescriptor, TestOutputEvent event) {
139+
registerEvent(testDescriptor, Event.OUTPUT)
140+
}
141+
142+
void registerEvent(TestDescriptorInternal testDescriptor, Event event) {
143+
events.putIfAbsent(testDescriptor, [])
144+
events[testDescriptor] << event
145+
}
146+
}
147+
"""
148+
}

0 commit comments

Comments
 (0)