|
@@ -25,6 +25,7 @@ import java.io.FileNotFoundException;
|
|
|
import java.io.IOException;
|
|
|
import java.util.concurrent.Callable;
|
|
|
import java.util.concurrent.TimeoutException;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
import static org.apache.hadoop.test.LambdaTestUtils.*;
|
|
|
import static org.apache.hadoop.test.GenericTestUtils.*;
|
|
@@ -123,6 +124,27 @@ public class TestLambdaTestUtils extends Assert {
|
|
|
minCount <= retry.getInvocationCount());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Raise an exception.
|
|
|
+ * @param e exception to raise
|
|
|
+ * @return never
|
|
|
+ * @throws Exception passed in exception
|
|
|
+ */
|
|
|
+ private boolean r(Exception e) throws Exception {
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Raise an error.
|
|
|
+ * @param e error to raise
|
|
|
+ * @return never
|
|
|
+ * @throws Exception never
|
|
|
+ * @throws Error the passed in error
|
|
|
+ */
|
|
|
+ private boolean r(Error e) throws Exception {
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
public void testAwaitAlwaysTrue() throws Throwable {
|
|
|
await(TIMEOUT,
|
|
@@ -140,7 +162,7 @@ public class TestLambdaTestUtils extends Assert {
|
|
|
TIMEOUT_FAILURE_HANDLER);
|
|
|
fail("should not have got here");
|
|
|
} catch (TimeoutException e) {
|
|
|
- assertTrue(retry.getInvocationCount() > 4);
|
|
|
+ assertMinRetryCount(1);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -316,9 +338,7 @@ public class TestLambdaTestUtils extends Assert {
|
|
|
IOException ioe = intercept(IOException.class,
|
|
|
() -> await(
|
|
|
TIMEOUT,
|
|
|
- () -> {
|
|
|
- throw new IOException("inner " + ++count);
|
|
|
- },
|
|
|
+ () -> r(new IOException("inner " + ++count)),
|
|
|
retry,
|
|
|
(timeout, ex) -> ex));
|
|
|
assertRetryCount(count - 1);
|
|
@@ -339,9 +359,7 @@ public class TestLambdaTestUtils extends Assert {
|
|
|
public void testInterceptAwaitFailFastLambda() throws Throwable {
|
|
|
intercept(FailFastException.class,
|
|
|
() -> await(TIMEOUT,
|
|
|
- () -> {
|
|
|
- throw new FailFastException("ffe");
|
|
|
- },
|
|
|
+ () -> r(new FailFastException("ffe")),
|
|
|
retry,
|
|
|
(timeout, ex) -> ex));
|
|
|
assertRetryCount(0);
|
|
@@ -361,14 +379,13 @@ public class TestLambdaTestUtils extends Assert {
|
|
|
assertRetryCount(0);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
@Test
|
|
|
public void testInterceptEventuallyLambdaFailures() throws Throwable {
|
|
|
intercept(IOException.class,
|
|
|
"oops",
|
|
|
() -> eventually(TIMEOUT,
|
|
|
- () -> {
|
|
|
- throw new IOException("oops");
|
|
|
- },
|
|
|
+ () -> r(new IOException("oops")),
|
|
|
retry));
|
|
|
assertMinRetryCount(1);
|
|
|
}
|
|
@@ -385,11 +402,95 @@ public class TestLambdaTestUtils extends Assert {
|
|
|
intercept(FailFastException.class, "oops",
|
|
|
() -> eventually(
|
|
|
TIMEOUT,
|
|
|
- () -> {
|
|
|
- throw new FailFastException("oops");
|
|
|
- },
|
|
|
+ () -> r(new FailFastException("oops")),
|
|
|
+ retry));
|
|
|
+ assertRetryCount(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Verify that assertions trigger catch and retry.
|
|
|
+ * @throws Throwable if the code is broken
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testEventuallySpinsOnAssertions() throws Throwable {
|
|
|
+ AtomicInteger counter = new AtomicInteger(0);
|
|
|
+ eventually(TIMEOUT,
|
|
|
+ () -> {
|
|
|
+ while (counter.incrementAndGet() < 5) {
|
|
|
+ fail("if you see this, we are in trouble");
|
|
|
+ }
|
|
|
+ },
|
|
|
+ retry);
|
|
|
+ assertMinRetryCount(4);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Verify that VirtualMachineError errors are immediately rethrown.
|
|
|
+ * @throws Throwable if the code is broken
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testInterceptEventuallyThrowsVMErrors() throws Throwable {
|
|
|
+ intercept(OutOfMemoryError.class, "OOM",
|
|
|
+ () -> eventually(
|
|
|
+ TIMEOUT,
|
|
|
+ () -> r(new OutOfMemoryError("OOM")),
|
|
|
retry));
|
|
|
assertRetryCount(0);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Verify that you can declare that an intercept will intercept Errors.
|
|
|
+ * @throws Throwable if the code is broken
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testInterceptHandlesErrors() throws Throwable {
|
|
|
+ intercept(OutOfMemoryError.class, "OOM",
|
|
|
+ () -> r(new OutOfMemoryError("OOM")));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Verify that if an Error raised is not the one being intercepted,
|
|
|
+ * it gets rethrown.
|
|
|
+ * @throws Throwable if the code is broken
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testInterceptRethrowsVMErrors() throws Throwable {
|
|
|
+ intercept(StackOverflowError.class, "",
|
|
|
+ () -> intercept(OutOfMemoryError.class, "",
|
|
|
+ () -> r(new StackOverflowError())));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testAwaitHandlesAssertions() throws Throwable {
|
|
|
+ // await a state which is never reached, expect a timeout exception
|
|
|
+ // with the text "failure" in it
|
|
|
+ TimeoutException ex = intercept(TimeoutException.class,
|
|
|
+ "failure",
|
|
|
+ () -> await(TIMEOUT,
|
|
|
+ () -> r(new AssertionError("failure")),
|
|
|
+ retry,
|
|
|
+ TIMEOUT_FAILURE_HANDLER));
|
|
|
+
|
|
|
+ // the retry handler must have been invoked
|
|
|
+ assertMinRetryCount(1);
|
|
|
+ // and the nested cause is tha raised assertion
|
|
|
+ if (!(ex.getCause() instanceof AssertionError)) {
|
|
|
+ throw ex;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testAwaitRethrowsVMErrors() throws Throwable {
|
|
|
+ // await a state which is never reached, expect a timeout exception
|
|
|
+ // with the text "failure" in it
|
|
|
+ intercept(StackOverflowError.class,
|
|
|
+ () -> await(TIMEOUT,
|
|
|
+ () -> r(new StackOverflowError()),
|
|
|
+ retry,
|
|
|
+ TIMEOUT_FAILURE_HANDLER));
|
|
|
+
|
|
|
+ // the retry handler must not have been invoked
|
|
|
+ assertMinRetryCount(0);
|
|
|
+ }
|
|
|
+
|
|
|
}
|