You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by ch...@apache.org on 2021/04/23 14:59:03 UTC
[flink] branch release-1.13 updated (7578b1d -> 2413649)
This is an automated email from the ASF dual-hosted git repository.
chesnay pushed a change to branch release-1.13
in repository https://gitbox.apache.org/repos/asf/flink.git.
from 7578b1d [FLINK-21659][coordination] Properly expose checkpoint settings for initializing jobs
new 4fefb62 [FLINK-20723][tests] Ignore expected exception when retrying
new b18db6b [FLINK-20723][tests] Allow retries to be defined per class
new 2413649 [FLINK-20723][cassandra][tests] Retry on NoHostAvailableException
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../cassandra/CassandraConnectorITCase.java | 8 +
.../flink/testutils/junit/RetryOnException.java | 16 +-
.../flink/testutils/junit/RetryOnFailure.java | 15 +-
.../apache/flink/testutils/junit/RetryRule.java | 69 +++++++--
.../flink/testutils/junit/RetryRuleTest.java | 165 +++++++++++++++++++++
5 files changed, 252 insertions(+), 21 deletions(-)
create mode 100644 flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java
[flink] 01/03: [FLINK-20723][tests] Ignore expected exception when
retrying
Posted by ch...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
chesnay pushed a commit to branch release-1.13
in repository https://gitbox.apache.org/repos/asf/flink.git
commit 4fefb626570359fedaaeac10ef855c7caaa307a6
Author: Chesnay Schepler <ch...@apache.org>
AuthorDate: Wed Apr 21 14:57:19 2021 +0200
[FLINK-20723][tests] Ignore expected exception when retrying
---
.../apache/flink/testutils/junit/RetryRule.java | 52 +++++++++----
.../flink/testutils/junit/RetryRuleTest.java | 88 ++++++++++++++++++++++
2 files changed, 126 insertions(+), 14 deletions(-)
diff --git a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java
index beb2f24..04fca6a 100644
--- a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java
+++ b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java
@@ -54,32 +54,38 @@ public class RetryRule implements TestRule {
RetryOnFailure retryOnFailure = description.getAnnotation(RetryOnFailure.class);
RetryOnException retryOnException = description.getAnnotation(RetryOnException.class);
- // sanity check that we don't use expected exceptions with the RetryOnX annotations
- if (retryOnFailure != null || retryOnException != null) {
- Test test = description.getAnnotation(Test.class);
- if (test.expected() != Test.None.class) {
- throw new IllegalArgumentException(
- "You cannot combine the RetryOnFailure "
- + "annotation with the Test(expected) annotation.");
- }
- }
-
// sanity check that we don't use both annotations
if (retryOnFailure != null && retryOnException != null) {
throw new IllegalArgumentException(
"You cannot combine the RetryOnFailure and RetryOnException annotations.");
}
+ final Class<? extends Throwable> whitelistedException = getExpectedException(description);
+
if (retryOnFailure != null) {
- return new RetryOnFailureStatement(retryOnFailure.times(), statement);
+ return new RetryOnFailureStatement(
+ retryOnFailure.times(), statement, whitelistedException);
} else if (retryOnException != null) {
return new RetryOnExceptionStatement(
- retryOnException.times(), retryOnException.exception(), statement);
+ retryOnException.times(),
+ retryOnException.exception(),
+ statement,
+ whitelistedException);
} else {
return statement;
}
}
+ @Nullable
+ private static Class<? extends Throwable> getExpectedException(Description description) {
+ Test test = description.getAnnotation(Test.class);
+ if (test.expected() != Test.None.class) {
+ return test.expected();
+ }
+
+ return null;
+ }
+
/** Retries a test in case of a failure. */
private static class RetryOnFailureStatement extends Statement {
@@ -88,8 +94,13 @@ public class RetryRule implements TestRule {
private int currentRun;
private final Statement statement;
+ @Nullable private final Class<? extends Throwable> expectedException;
- private RetryOnFailureStatement(int timesOnFailure, Statement statement) {
+ private RetryOnFailureStatement(
+ int timesOnFailure,
+ Statement statement,
+ @Nullable Class<? extends Throwable> expectedException) {
+ this.expectedException = expectedException;
if (timesOnFailure < 0) {
throw new IllegalArgumentException("Negatives number of retries on failure");
}
@@ -109,6 +120,11 @@ public class RetryRule implements TestRule {
statement.evaluate();
break; // success
} catch (Throwable t) {
+ if (expectedException != null
+ && expectedException.isAssignableFrom(t.getClass())) {
+ throw t;
+ }
+
LOG.warn(
String.format(
"Test run failed (%d/%d).", currentRun, timesOnFailure + 1),
@@ -129,13 +145,15 @@ public class RetryRule implements TestRule {
private final Class<? extends Throwable> exceptionClass;
private final int timesOnFailure;
private final Statement statement;
+ @Nullable private final Class<? extends Throwable> expectedException;
private int currentRun;
private RetryOnExceptionStatement(
int timesOnFailure,
Class<? extends Throwable> exceptionClass,
- Statement statement) {
+ Statement statement,
+ @Nullable Class<? extends Throwable> expectedException) {
if (timesOnFailure < 0) {
throw new IllegalArgumentException("Negatives number of retries on failure");
}
@@ -146,6 +164,7 @@ public class RetryRule implements TestRule {
this.exceptionClass = (exceptionClass);
this.timesOnFailure = timesOnFailure;
this.statement = statement;
+ this.expectedException = expectedException;
}
/**
@@ -160,6 +179,11 @@ public class RetryRule implements TestRule {
statement.evaluate();
break; // success
} catch (Throwable t) {
+ if (expectedException != null
+ && expectedException.isAssignableFrom(t.getClass())) {
+ throw t;
+ }
+
LOG.warn(
String.format(
"Test run failed (%d/%d).", currentRun, timesOnFailure + 1),
diff --git a/flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java b/flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java
new file mode 100644
index 0000000..e2e3401
--- /dev/null
+++ b/flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.testutils.junit;
+
+import org.apache.flink.util.TestLogger;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/** Tests for the {@link RetryRule}. */
+public class RetryRuleTest extends TestLogger {
+
+ @Test
+ public void testExpectedExceptionIgnored() throws Throwable {
+ final RetryRule retryRule = new RetryRule();
+
+ final Description testDescription =
+ Description.createTestDescription(
+ TestClassWithTestExpectingRuntimeException.class,
+ "test",
+ TestClassWithTestExpectingRuntimeException.class
+ .getMethod("test")
+ .getAnnotations());
+
+ final TestStatement statement = new TestStatement(1);
+
+ try {
+ retryRule.apply(statement, testDescription).evaluate();
+ Assert.fail("Should have failed.");
+ } catch (RuntimeException expected) {
+ }
+
+ assertThat(statement.getNumEvaluations(), is(1));
+ }
+
+ @Ignore // we don't want to actually this run as a test
+ private static class TestClassWithTestExpectingRuntimeException {
+ @RetryOnFailure(times = 2)
+ @Test(expected = RuntimeException.class)
+ public void test() {}
+ }
+
+ private static class TestStatement extends Statement {
+ private final int numEvaluationsToFail;
+
+ private int numEvaluations = 0;
+
+ private TestStatement(int numEvaluationsToFail) {
+ this.numEvaluationsToFail = numEvaluationsToFail;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ if (numEvaluations < numEvaluationsToFail) {
+ throw new RuntimeException("test exception");
+ }
+ } finally {
+ numEvaluations++;
+ }
+ }
+
+ public int getNumEvaluations() {
+ return numEvaluations;
+ }
+ }
+}
[flink] 03/03: [FLINK-20723][cassandra][tests] Retry on
NoHostAvailableException
Posted by ch...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
chesnay pushed a commit to branch release-1.13
in repository https://gitbox.apache.org/repos/asf/flink.git
commit 2413649b0c04b72a38e57d0a57f71d9ff5919274
Author: Chesnay Schepler <ch...@apache.org>
AuthorDate: Wed Apr 21 15:10:49 2021 +0200
[FLINK-20723][cassandra][tests] Retry on NoHostAvailableException
---
.../streaming/connectors/cassandra/CassandraConnectorITCase.java | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/flink-connectors/flink-connector-cassandra/src/test/java/org/apache/flink/streaming/connectors/cassandra/CassandraConnectorITCase.java b/flink-connectors/flink-connector-cassandra/src/test/java/org/apache/flink/streaming/connectors/cassandra/CassandraConnectorITCase.java
index 0b79877..1f7a34f 100644
--- a/flink-connectors/flink-connector-cassandra/src/test/java/org/apache/flink/streaming/connectors/cassandra/CassandraConnectorITCase.java
+++ b/flink-connectors/flink-connector-cassandra/src/test/java/org/apache/flink/streaming/connectors/cassandra/CassandraConnectorITCase.java
@@ -47,6 +47,8 @@ import org.apache.flink.streaming.runtime.operators.WriteAheadSinkTestBase;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
import org.apache.flink.table.api.internal.TableEnvironmentInternal;
import org.apache.flink.testutils.junit.FailsOnJava11;
+import org.apache.flink.testutils.junit.RetryOnException;
+import org.apache.flink.testutils.junit.RetryRule;
import org.apache.flink.types.Row;
import com.datastax.driver.core.Cluster;
@@ -54,6 +56,7 @@ import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.QueryOptions;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Session;
+import com.datastax.driver.core.exceptions.NoHostAvailableException;
import com.datastax.driver.mapping.Mapper;
import org.apache.cassandra.service.CassandraDaemon;
import org.junit.AfterClass;
@@ -61,6 +64,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
@@ -92,6 +96,8 @@ import static org.junit.Assert.assertTrue;
/** IT cases for all cassandra sinks. */
@SuppressWarnings("serial")
@Category(FailsOnJava11.class)
+// this test is known to be unstable, but the exact cause is unknown
+@RetryOnException(times = 2, exception = NoHostAvailableException.class)
public class CassandraConnectorITCase
extends WriteAheadSinkTestBase<
Tuple3<String, Integer, Integer>,
@@ -99,6 +105,8 @@ public class CassandraConnectorITCase
private static final Logger LOG = LoggerFactory.getLogger(CassandraConnectorITCase.class);
+ @Rule public final RetryRule retryRule = new RetryRule();
+
private static final boolean EMBEDDED = true;
private static EmbeddedCassandraService cassandra;
[flink] 02/03: [FLINK-20723][tests] Allow retries to be defined per
class
Posted by ch...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
chesnay pushed a commit to branch release-1.13
in repository https://gitbox.apache.org/repos/asf/flink.git
commit b18db6b75847d35c7edb33c2c3c7c6e02098fe67
Author: Chesnay Schepler <ch...@apache.org>
AuthorDate: Wed Apr 21 15:10:24 2021 +0200
[FLINK-20723][tests] Allow retries to be defined per class
---
.../flink/testutils/junit/RetryOnException.java | 16 +++-
.../flink/testutils/junit/RetryOnFailure.java | 15 +++-
.../apache/flink/testutils/junit/RetryRule.java | 21 +++++-
.../flink/testutils/junit/RetryRuleTest.java | 85 +++++++++++++++++++++-
4 files changed, 124 insertions(+), 13 deletions(-)
diff --git a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnException.java b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnException.java
index e5a61a8..74193ac 100644
--- a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnException.java
+++ b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnException.java
@@ -18,6 +18,7 @@
package org.apache.flink.testutils.junit;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -25,23 +26,30 @@ import java.lang.annotation.Target;
/**
* Annotation to use with {@link org.apache.flink.testutils.junit.RetryRule}.
*
- * <p>Add the {@link org.apache.flink.testutils.junit.RetryRule} to your test and annotate tests
- * with {@link RetryOnException}.
+ * <p>Add the {@link org.apache.flink.testutils.junit.RetryRule} to your test class and annotate the
+ * class and/or tests with {@link RetryOnException}.
*
* <pre>
+ * {@literal @}RetryOnException(times=1, exception=IOException.class)
* public class YourTest {
*
* {@literal @}Rule
* public RetryRule retryRule = new RetryRule();
*
* {@literal @}Test
- * {@literal @}RetryOnException(times=1, exception=IOException.class)
* public void yourTest() throws Exception {
* // This will be retried 1 time (total runs 2) before failing the test.
* throw new IOException("Failing test");
* }
*
* {@literal @}Test
+ * {@literal @}RetryOnException(times=2, exception=IOException.class)
+ * public void yourTest() throws Exception {
+ * // This will be retried 2 times (total runs 3) before failing the test.
+ * throw new IOException("Failing test");
+ * }
+ *
+ * {@literal @}Test
* {@literal @}RetryOnException(times=1, exception=IOException.class)
* public void yourTest() throws Exception {
* // This will not be retried, because it throws the wrong exception
@@ -51,7 +59,7 @@ import java.lang.annotation.Target;
* </pre>
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target(java.lang.annotation.ElementType.METHOD)
+@Target({java.lang.annotation.ElementType.METHOD, ElementType.TYPE})
public @interface RetryOnException {
int times();
diff --git a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnFailure.java b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnFailure.java
index 13dd9df..84c0614 100644
--- a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnFailure.java
+++ b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryOnFailure.java
@@ -18,6 +18,7 @@
package org.apache.flink.testutils.junit;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -25,25 +26,33 @@ import java.lang.annotation.Target;
/**
* Annotation to use with {@link RetryRule}.
*
- * <p>Add the {@link RetryRule} to your test and annotate tests with {@link RetryOnFailure}.
+ * <p>Add the {@link RetryRule} to your test class and annotate the class and/or tests with {@link
+ * RetryOnFailure}.
*
* <pre>
+ * {@literal @}RetryOnFailure(times=1)
* public class YourTest {
*
* {@literal @}Rule
* public RetryRule retryRule = new RetryRule();
*
* {@literal @}Test
- * {@literal @}RetryOnFailure(times=1)
* public void yourTest() {
* // This will be retried 1 time (total runs 2) before failing the test.
* throw new Exception("Failing test");
* }
+ *
+ * {@literal @}Test
+ * {@literal @}RetryOnFailure(times=2)
+ * public void yourTest() {
+ * // This will be retried 2 time (total runs 3) before failing the test.
+ * throw new Exception("Failing test");
+ * }
* }
* </pre>
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({java.lang.annotation.ElementType.METHOD})
+@Target({java.lang.annotation.ElementType.METHOD, ElementType.TYPE})
public @interface RetryOnFailure {
int times();
}
diff --git a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java
index 04fca6a..9826487 100644
--- a/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java
+++ b/flink-test-utils-parent/flink-test-utils-junit/src/main/java/org/apache/flink/testutils/junit/RetryRule.java
@@ -25,23 +25,34 @@ import org.junit.runners.model.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nullable;
+
/**
* A rule to retry failed tests for a fixed number of times.
*
- * <p>Add the {@link RetryRule} to your test and annotate tests with {@link RetryOnFailure}.
+ * <p>Add the {@link RetryRule} to your test class and annotate the class and/or tests with either
+ * {@link RetryOnFailure} or {@link RetryOnException}. If both the class and test are annotated,
+ * then only the latter annotation is taken into account.
*
* <pre>
+ * {@literal @}RetryOnFailure(times=1)
* public class YourTest {
*
* {@literal @}Rule
* public RetryRule retryRule = new RetryRule();
*
* {@literal @}Test
- * {@literal @}RetryOnFailure(times=1)
* public void yourTest() {
* // This will be retried 1 time (total runs 2) before failing the test.
* throw new Exception("Failing test");
* }
+ *
+ * {@literal @}Test
+ * {@literal @}RetryOnFailure(times=2)
+ * public void yourTest() {
+ * // This will be retried 2 time (total runs 3) before failing the test.
+ * throw new Exception("Failing test");
+ * }
* }
* </pre>
*/
@@ -54,6 +65,12 @@ public class RetryRule implements TestRule {
RetryOnFailure retryOnFailure = description.getAnnotation(RetryOnFailure.class);
RetryOnException retryOnException = description.getAnnotation(RetryOnException.class);
+ if (retryOnFailure == null && retryOnException == null) {
+ // if nothing is specified on the test method, fall back to annotations on the class
+ retryOnFailure = description.getTestClass().getAnnotation(RetryOnFailure.class);
+ retryOnException = description.getTestClass().getAnnotation(RetryOnException.class);
+ }
+
// sanity check that we don't use both annotations
if (retryOnFailure != null && retryOnException != null) {
throw new IllegalArgumentException(
diff --git a/flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java b/flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java
index e2e3401..527ebc6 100644
--- a/flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java
+++ b/flink-test-utils-parent/flink-test-utils-junit/src/test/java/org/apache/flink/testutils/junit/RetryRuleTest.java
@@ -30,10 +30,11 @@ import static org.junit.Assert.assertThat;
/** Tests for the {@link RetryRule}. */
public class RetryRuleTest extends TestLogger {
+ private static final RetryRule RETRY_RULE = new RetryRule();
@Test
public void testExpectedExceptionIgnored() throws Throwable {
- final RetryRule retryRule = new RetryRule();
+ final int numEvaluationsToFail = 1;
final Description testDescription =
Description.createTestDescription(
@@ -43,15 +44,15 @@ public class RetryRuleTest extends TestLogger {
.getMethod("test")
.getAnnotations());
- final TestStatement statement = new TestStatement(1);
+ final TestStatement statement = new TestStatement(numEvaluationsToFail);
try {
- retryRule.apply(statement, testDescription).evaluate();
+ RETRY_RULE.apply(statement, testDescription).evaluate();
Assert.fail("Should have failed.");
} catch (RuntimeException expected) {
}
- assertThat(statement.getNumEvaluations(), is(1));
+ assertThat(statement.getNumEvaluations(), is(numEvaluationsToFail));
}
@Ignore // we don't want to actually this run as a test
@@ -61,6 +62,82 @@ public class RetryRuleTest extends TestLogger {
public void test() {}
}
+ @Test
+ public void testNoAnnotationResultsInZeroRetries() throws Throwable {
+ final int numEvaluationsToFail = 1;
+
+ final Description testDescription =
+ Description.createTestDescription(
+ TestClassWithoutAnnotation.class,
+ "test",
+ TestClassWithAnnotation.class.getMethod("test").getAnnotations());
+
+ final TestStatement statement = new TestStatement(numEvaluationsToFail);
+
+ try {
+ RETRY_RULE.apply(statement, testDescription).evaluate();
+ Assert.fail("Should have failed.");
+ } catch (RuntimeException expected) {
+ }
+
+ assertThat(statement.getNumEvaluations(), is(numEvaluationsToFail));
+ }
+
+ @Ignore // we don't want to actually this run as a test
+ private static class TestClassWithoutAnnotation {
+ @Test
+ public void test() {}
+ }
+
+ @Test
+ public void testAnnotationOnClassUsedAsFallback() throws Throwable {
+ final int numEvaluationsToFail = 1;
+
+ final Description testDescription =
+ Description.createTestDescription(
+ TestClassWithAnnotation.class,
+ "test",
+ TestClassWithAnnotation.class.getMethod("test").getAnnotations());
+
+ final TestStatement statement = new TestStatement(numEvaluationsToFail);
+
+ RETRY_RULE.apply(statement, testDescription).evaluate();
+
+ assertThat(statement.getNumEvaluations(), is(numEvaluationsToFail + 1));
+ }
+
+ @Ignore // we don't want to actually this run as a test
+ @RetryOnFailure(times = 1)
+ private static class TestClassWithAnnotation {
+ @Test
+ public void test() {}
+ }
+
+ @Test
+ public void testAnnotationOnMethodTakesPrecedence() throws Throwable {
+ final int numEvaluationsToFail = 2;
+
+ final Description testDescription =
+ Description.createTestDescription(
+ TestClassWithAnnotationOnMethod.class,
+ "test",
+ TestClassWithAnnotationOnMethod.class.getMethod("test").getAnnotations());
+
+ final TestStatement statement = new TestStatement(numEvaluationsToFail);
+
+ RETRY_RULE.apply(statement, testDescription).evaluate();
+
+ assertThat(statement.getNumEvaluations(), is(numEvaluationsToFail + 1));
+ }
+
+ @Ignore // we don't want to actually this run as a test
+ @RetryOnFailure(times = 1)
+ private static class TestClassWithAnnotationOnMethod {
+ @RetryOnFailure(times = 2)
+ @Test
+ public void test() {}
+ }
+
private static class TestStatement extends Statement {
private final int numEvaluationsToFail;