blob: 29082a65045db7cdee02ef174df55925081f49f3 [file] [log] [blame]
/*
* 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.hadoop.test;
import org.junit.Assert;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeoutException;
import static org.apache.hadoop.test.LambdaTestUtils.*;
import static org.apache.hadoop.test.GenericTestUtils.*;
/**
* Test the logic in {@link LambdaTestUtils}.
* This test suite includes Java 8 and Java 7 code; the Java 8 code exists
* to verify that the API is easily used with Lambda expressions.
*/
public class TestLambdaTestUtils extends Assert {
public static final int INTERVAL = 10;
public static final int TIMEOUT = 50;
private FixedRetryInterval retry = new FixedRetryInterval(INTERVAL);
/**
* Always evaluates to true.
*/
public static final Callable<Boolean> ALWAYS_TRUE =
new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return true;
}
};
/**
* Always evaluates to false.
*/
public static final Callable<Boolean> ALWAYS_FALSE =
new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return false;
}
};
/**
* Text in the raised FNFE.
*/
public static final String MISSING = "not found";
/**
* A predicate that always throws a FileNotFoundException.
*/
public static final Callable<Boolean> ALWAYS_FNFE =
new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
throw new FileNotFoundException(MISSING);
}
};
/**
* reusable timeout handler.
*/
public static final GenerateTimeout
TIMEOUT_FAILURE_HANDLER = new GenerateTimeout();
/**
* Always evaluates to 3L.
*/
public static final Callable<Long> EVAL_3L = new Callable<Long>() {
@Override
public Long call() throws Exception {
return 3L;
}
};
/**
* Always raises a {@code FileNotFoundException}.
*/
public static final Callable<Long> EVAL_FNFE = new Callable<Long>() {
@Override
public Long call() throws Exception {
throw new FileNotFoundException(MISSING);
}
};
/**
* Assert the retry count is as expected.
* @param expected expected value
*/
protected void assertRetryCount(int expected) {
assertEquals(retry.toString(), expected, retry.getInvocationCount());
}
/**
* Assert the retry count is as expected.
* @param minCount minimum value
*/
protected void assertMinRetryCount(int minCount) {
assertTrue("retry count of " + retry + " is not >= " + minCount,
minCount <= retry.getInvocationCount());
}
@Test
public void testAwaitAlwaysTrue() throws Throwable {
await(TIMEOUT,
ALWAYS_TRUE,
new FixedRetryInterval(INTERVAL),
TIMEOUT_FAILURE_HANDLER);
}
@Test
public void testAwaitAlwaysFalse() throws Throwable {
try {
await(TIMEOUT,
ALWAYS_FALSE,
retry,
TIMEOUT_FAILURE_HANDLER);
fail("should not have got here");
} catch (TimeoutException e) {
assertMinRetryCount(1);
}
}
@Test
public void testAwaitLinearRetry() throws Throwable {
ProportionalRetryInterval linearRetry =
new ProportionalRetryInterval(INTERVAL * 2, TIMEOUT * 2);
try {
await(TIMEOUT,
ALWAYS_FALSE,
linearRetry,
TIMEOUT_FAILURE_HANDLER);
fail("should not have got here");
} catch (TimeoutException e) {
assertEquals(linearRetry.toString(),
2, linearRetry.getInvocationCount());
}
}
@Test
public void testAwaitFNFE() throws Throwable {
try {
await(TIMEOUT,
ALWAYS_FNFE,
retry,
TIMEOUT_FAILURE_HANDLER);
fail("should not have got here");
} catch (TimeoutException e) {
// inner clause is included
assertTrue(retry.getInvocationCount() > 0);
assertTrue(e.getCause() instanceof FileNotFoundException);
assertExceptionContains(MISSING, e);
}
}
@Test
public void testRetryInterval() throws Throwable {
ProportionalRetryInterval interval =
new ProportionalRetryInterval(200, 1000);
assertEquals(200, (int) interval.call());
assertEquals(400, (int) interval.call());
assertEquals(600, (int) interval.call());
assertEquals(800, (int) interval.call());
assertEquals(1000, (int) interval.call());
assertEquals(1000, (int) interval.call());
assertEquals(1000, (int) interval.call());
}
@Test
public void testInterceptSuccess() throws Throwable {
IOException ioe = intercept(IOException.class, ALWAYS_FNFE);
assertExceptionContains(MISSING, ioe);
}
@Test
public void testInterceptContains() throws Throwable {
intercept(IOException.class, MISSING, ALWAYS_FNFE);
}
@Test
public void testInterceptContainsWrongString() throws Throwable {
try {
FileNotFoundException e =
intercept(FileNotFoundException.class, "404", ALWAYS_FNFE);
assertNotNull(e);
throw e;
} catch (AssertionError expected) {
assertExceptionContains(MISSING, expected);
}
}
@Test
public void testInterceptVoidCallable() throws Throwable {
intercept(AssertionError.class,
NULL_RESULT,
new Callable<IOException>() {
@Override
public IOException call() throws Exception {
return intercept(IOException.class,
new Callable<Void>() {
@Override
public Void call() throws Exception {
return null;
}
});
}
});
}
@Test
public void testEventually() throws Throwable {
long result = eventually(TIMEOUT, EVAL_3L, retry);
assertEquals(3, result);
assertEquals(0, retry.getInvocationCount());
}
@Test
public void testEventuallyFailuresRetry() throws Throwable {
try {
eventually(TIMEOUT, EVAL_FNFE, retry);
fail("should not have got here");
} catch (IOException expected) {
// expected
assertMinRetryCount(1);
}
}
}