Skip to content

Commit a80e6ed

Browse files
committed
Add failOnSkippedAfterRetry option
Signed-off-by: Alexander Boyarshinov <[email protected]>
1 parent 05138d3 commit a80e6ed

File tree

7 files changed

+62
-3
lines changed

7 files changed

+62
-3
lines changed

README.adoc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ test {
4747
maxRetries = 2
4848
maxFailures = 20
4949
failOnPassedAfterRetry = true
50+
failOnSkippedAfterRetry = true
5051
}
5152
}
5253
----
@@ -60,6 +61,7 @@ test {
6061
maxRetries.set(2)
6162
maxFailures.set(20)
6263
failOnPassedAfterRetry.set(true)
64+
failOnSkippedAfterRetry.set(true)
6365
}
6466
}
6567
----
@@ -79,6 +81,7 @@ test {
7981
maxFailures = 20
8082
}
8183
failOnPassedAfterRetry = true
84+
failOnSkippedAfterRetry = true
8285
}
8386
}
8487
----
@@ -120,6 +123,18 @@ public interface TestRetryTaskExtension {
120123
*/
121124
Property<Boolean> getFailOnPassedAfterRetry();
122125
126+
/**
127+
* Whether tests that initially fail and then skip on retry should fail the task.
128+
* <p>
129+
* This setting defaults to {@code true} (for backward compatibility),
130+
* which results in the task failing if any of tests skip on retry.
131+
* <p>
132+
* This setting has no effect if {@link Test#getIgnoreFailures()} is set to true.
133+
*
134+
* @return whether tests that initially fails and then skip on retry should fail the task
135+
*/
136+
Property<Boolean> getFailOnSkippedAfterRetry();
137+
123138
/**
124139
* The maximum number of times to retry an individual test.
125140
* <p>

plugin/src/main/java/org/gradle/testretry/TestRetryTaskExtension.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ public interface TestRetryTaskExtension {
4444
*/
4545
Property<Boolean> getFailOnPassedAfterRetry();
4646

47+
/**
48+
* Whether tests that initially fail and then skip on retry should fail the task.
49+
* <p>
50+
* This setting defaults to {@code true} (for backward compatibility),
51+
* which results in the task failing if any of tests skip on retry.
52+
* <p>
53+
* This setting has no effect if {@link Test#getIgnoreFailures()} is set to true.
54+
*
55+
* @return whether tests that initially fails and then skip on retry should fail the task
56+
*/
57+
Property<Boolean> getFailOnSkippedAfterRetry();
58+
4759
/**
4860
* The maximum number of times to retry an individual test.
4961
* <p>

plugin/src/main/java/org/gradle/testretry/internal/config/DefaultTestRetryTaskExtension.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
public class DefaultTestRetryTaskExtension implements TestRetryTaskExtension {
2727

2828
private final Property<Boolean> failOnPassedAfterRetry;
29+
private final Property<Boolean> failOnSkippedAfterRetry;
2930
private final Property<Integer> maxRetries;
3031
private final Property<Integer> maxFailures;
3132
private final Filter filter;
@@ -35,6 +36,7 @@ public class DefaultTestRetryTaskExtension implements TestRetryTaskExtension {
3536
@Inject
3637
public DefaultTestRetryTaskExtension(ObjectFactory objects) {
3738
this.failOnPassedAfterRetry = objects.property(Boolean.class);
39+
this.failOnSkippedAfterRetry = objects.property(Boolean.class);
3840
this.maxRetries = objects.property(Integer.class);
3941
this.maxFailures = objects.property(Integer.class);
4042
this.filter = new FilterImpl(objects);
@@ -45,6 +47,10 @@ public Property<Boolean> getFailOnPassedAfterRetry() {
4547
return failOnPassedAfterRetry;
4648
}
4749

50+
public Property<Boolean> getFailOnSkippedAfterRetry() {
51+
return failOnSkippedAfterRetry;
52+
}
53+
4854
public Property<Integer> getMaxRetries() {
4955
return maxRetries;
5056
}

plugin/src/main/java/org/gradle/testretry/internal/config/TestRetryTaskExtensionAccessor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public interface TestRetryTaskExtensionAccessor {
2121

2222
boolean getFailOnPassedAfterRetry();
2323

24+
boolean getFailOnSkippedAfterRetry();
25+
2426
int getMaxRetries();
2527

2628
int getMaxFailures();

plugin/src/main/java/org/gradle/testretry/internal/config/TestRetryTaskExtensionAdapter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public final class TestRetryTaskExtensionAdapter implements TestRetryTaskExtensi
3636
private static final int DEFAULT_MAX_RETRIES = 0;
3737
private static final int DEFAULT_MAX_FAILURES = 0;
3838
private static final boolean DEFAULT_FAIL_ON_PASSED_AFTER_RETRY = false;
39+
private static final boolean DEFAULT_FAIL_ON_SKIPPED_AFTER_RETRY = true;
3940

4041
private final ProviderFactory providerFactory;
4142
private final TestRetryTaskExtension extension;
@@ -98,6 +99,11 @@ public boolean getFailOnPassedAfterRetry() {
9899
return read(extension.getFailOnPassedAfterRetry(), DEFAULT_FAIL_ON_PASSED_AFTER_RETRY);
99100
}
100101

102+
@Override
103+
public boolean getFailOnSkippedAfterRetry() {
104+
return read(extension.getFailOnPassedAfterRetry(), DEFAULT_FAIL_ON_SKIPPED_AFTER_RETRY);
105+
}
106+
101107
@Override
102108
public int getMaxRetries() {
103109
return read(extension.getMaxRetries(), DEFAULT_MAX_RETRIES);

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public void execute(JvmTestExecutionSpec spec, TestResultProcessor testResultPro
7272
int maxRetries = extension.getMaxRetries();
7373
int maxFailures = extension.getMaxFailures();
7474
boolean failOnPassedAfterRetry = extension.getFailOnPassedAfterRetry();
75+
boolean failOnSkippedAfterRetry = extension.getFailOnPassedAfterRetry();
7576

7677
if (maxRetries <= 0) {
7778
delegate.execute(spec, testResultProcessor);
@@ -106,7 +107,8 @@ public void execute(JvmTestExecutionSpec spec, TestResultProcessor testResultPro
106107
classRetryMatcher,
107108
frameworkTemplate.testsReader,
108109
testResultProcessor,
109-
maxFailures
110+
maxFailures,
111+
failOnSkippedAfterRetry
110112
);
111113

112114
int retryCount = 0;

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ final class RetryTestResultProcessor implements TestResultProcessor {
4747
private final TestResultProcessor delegate;
4848

4949
private final int maxFailures;
50+
private final boolean failOnSkippedAfterRetry;
5051
private boolean lastRetry;
5152
private boolean hasRetryFilteredFailures;
5253
private Method failureMethod;
@@ -66,14 +67,16 @@ final class RetryTestResultProcessor implements TestResultProcessor {
6667
ClassRetryMatcher classRetryMatcher,
6768
TestsReader testsReader,
6869
TestResultProcessor delegate,
69-
int maxFailures
70+
int maxFailures,
71+
boolean failOnSkippedAfterRetry
7072
) {
7173
this.testFrameworkStrategy = testFrameworkStrategy;
7274
this.filter = filter;
7375
this.classRetryMatcher = classRetryMatcher;
7476
this.testsReader = testsReader;
7577
this.delegate = delegate;
7678
this.maxFailures = maxFailures;
79+
this.failOnSkippedAfterRetry = failOnSkippedAfterRetry;
7780
}
7881

7982
@Override
@@ -108,7 +111,12 @@ public void completed(Object testId, TestCompleteEvent testCompleteEvent) {
108111

109112
boolean failedInPreviousRound = previousRoundFailedTests.remove(className, name);
110113
if (failedInPreviousRound && testCompleteEvent.getResultType() == SKIPPED) {
111-
addRetry(descriptor);
114+
if (failOnSkippedAfterRetry) {
115+
addRetry(descriptor);
116+
} else {
117+
emitFakeSkippedEvent(descriptor, testCompleteEvent, name);
118+
return;
119+
}
112120
}
113121

114122
// class-level lifecycle failures do not guarantee that all methods that failed in the previous round will be re-executed (e.g. due to class setup failure)
@@ -209,6 +217,14 @@ private void emitFakePassedEvent(TestDescriptorInternal parent, TestCompleteEven
209217
delegate.completed(syntheticTestId, new TestCompleteEvent(timestamp));
210218
}
211219

220+
private void emitFakeSkippedEvent(TestDescriptorInternal parent, TestCompleteEvent parentEvent, String name) {
221+
Object syntheticTestId = new Object();
222+
TestDescriptorInternal syntheticDescriptor = new TestDescriptorImpl(syntheticTestId, parent, name);
223+
long timestamp = parentEvent.getEndTime();
224+
delegate.started(syntheticDescriptor, new TestStartEvent(timestamp, parent.getId()));
225+
delegate.completed(syntheticTestId, new TestCompleteEvent(timestamp, SKIPPED));
226+
}
227+
212228
private boolean isClassDescriptor(TestDescriptorInternal descriptor) {
213229
return descriptor.getClassName() != null && descriptor.getClassName().equals(descriptor.getName());
214230
}

0 commit comments

Comments
 (0)