blob: 26a44b77fe5506e35ba40fa62b3e74d9d96e0452 [file] [log] [blame]
/*
* Copyright (C) 2006 The Guava Authors
*
* Licensed 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 com.google.common.util.concurrent;
import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Range;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
import junit.framework.TestCase;
/**
* Unit test for {@link SimpleTimeLimiter}.
*
* @author kevinb
* @author Jens Nyman
*/
public class SimpleTimeLimiterTest extends TestCase {
private static final long DELAY_MS = 50;
private static final long ENOUGH_MS = 500;
private static final long NOT_ENOUGH_MS = 5;
private static final String GOOD_CALLABLE_RESULT = "good callable result";
private static final Callable<String> GOOD_CALLABLE =
new Callable<String>() {
@Override
public String call() throws InterruptedException {
MILLISECONDS.sleep(DELAY_MS);
return GOOD_CALLABLE_RESULT;
}
};
private static final Callable<String> BAD_CALLABLE =
new Callable<String>() {
@Override
public String call() throws InterruptedException, SampleException {
MILLISECONDS.sleep(DELAY_MS);
throw new SampleException();
}
};
private static final Runnable GOOD_RUNNABLE =
new Runnable() {
@Override
public void run() {
try {
MILLISECONDS.sleep(DELAY_MS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
private static final Runnable BAD_RUNNABLE =
new Runnable() {
@Override
public void run() {
try {
MILLISECONDS.sleep(DELAY_MS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
throw new SampleRuntimeException();
}
};
private TimeLimiter service;
private static final ExecutorService executor = Executors.newFixedThreadPool(1);
@Override
protected void setUp() throws Exception {
super.setUp();
service = SimpleTimeLimiter.create(executor);
}
public void testNewProxy_goodMethodWithEnoughTime() throws Exception {
SampleImpl target = new SampleImpl(DELAY_MS);
Sample proxy = service.newProxy(target, Sample.class, ENOUGH_MS, MILLISECONDS);
Stopwatch stopwatch = Stopwatch.createStarted();
String result = proxy.sleepThenReturnInput("x");
assertThat(result).isEqualTo("x");
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
assertThat(target.finished).isTrue();
}
public void testNewProxy_goodMethodWithNotEnoughTime() throws Exception {
SampleImpl target = new SampleImpl(9999);
Sample proxy = service.newProxy(target, Sample.class, NOT_ENOUGH_MS, MILLISECONDS);
Stopwatch stopwatch = Stopwatch.createStarted();
try {
proxy.sleepThenReturnInput("x");
fail("no exception thrown");
} catch (UncheckedTimeoutException expected) {
}
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(NOT_ENOUGH_MS, DELAY_MS * 2));
// Is it still computing away anyway?
assertThat(target.finished).isFalse();
MILLISECONDS.sleep(ENOUGH_MS);
assertThat(target.finished).isFalse();
}
public void testNewProxy_badMethodWithEnoughTime() throws Exception {
SampleImpl target = new SampleImpl(DELAY_MS);
Sample proxy = service.newProxy(target, Sample.class, ENOUGH_MS, MILLISECONDS);
Stopwatch stopwatch = Stopwatch.createStarted();
try {
proxy.sleepThenThrowException();
fail("no exception thrown");
} catch (SampleException expected) {
}
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
}
public void testNewProxy_badMethodWithNotEnoughTime() throws Exception {
SampleImpl target = new SampleImpl(9999);
Sample proxy = service.newProxy(target, Sample.class, NOT_ENOUGH_MS, MILLISECONDS);
Stopwatch stopwatch = Stopwatch.createStarted();
try {
proxy.sleepThenThrowException();
fail("no exception thrown");
} catch (UncheckedTimeoutException expected) {
}
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(NOT_ENOUGH_MS, DELAY_MS * 2));
}
public void testCallWithTimeout_goodCallableWithEnoughTime() throws Exception {
Stopwatch stopwatch = Stopwatch.createStarted();
String result = service.callWithTimeout(GOOD_CALLABLE, ENOUGH_MS, MILLISECONDS);
assertThat(result).isEqualTo(GOOD_CALLABLE_RESULT);
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
}
public void testCallWithTimeout_goodCallableWithNotEnoughTime() throws Exception {
try {
service.callWithTimeout(GOOD_CALLABLE, NOT_ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (TimeoutException expected) {
}
}
public void testCallWithTimeout_badCallableWithEnoughTime() throws Exception {
try {
service.callWithTimeout(BAD_CALLABLE, ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (ExecutionException expected) {
assertThat(expected.getCause()).isInstanceOf(SampleException.class);
}
}
public void testCallUninterruptiblyWithTimeout_goodCallableWithEnoughTime() throws Exception {
Stopwatch stopwatch = Stopwatch.createStarted();
String result = service.callUninterruptiblyWithTimeout(GOOD_CALLABLE, ENOUGH_MS, MILLISECONDS);
assertThat(result).isEqualTo(GOOD_CALLABLE_RESULT);
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
}
public void testCallUninterruptiblyWithTimeout_goodCallableWithNotEnoughTime() throws Exception {
try {
service.callUninterruptiblyWithTimeout(GOOD_CALLABLE, NOT_ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (TimeoutException expected) {
}
}
public void testCallUninterruptiblyWithTimeout_badCallableWithEnoughTime() throws Exception {
try {
service.callUninterruptiblyWithTimeout(BAD_CALLABLE, ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (ExecutionException expected) {
assertThat(expected.getCause()).isInstanceOf(SampleException.class);
}
}
public void testRunWithTimeout_goodRunnableWithEnoughTime() throws Exception {
Stopwatch stopwatch = Stopwatch.createStarted();
service.runWithTimeout(GOOD_RUNNABLE, ENOUGH_MS, MILLISECONDS);
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
}
public void testRunWithTimeout_goodRunnableWithNotEnoughTime() throws Exception {
try {
service.runWithTimeout(GOOD_RUNNABLE, NOT_ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (TimeoutException expected) {
}
}
public void testRunWithTimeout_badRunnableWithEnoughTime() throws Exception {
try {
service.runWithTimeout(BAD_RUNNABLE, ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (UncheckedExecutionException expected) {
assertThat(expected.getCause()).isInstanceOf(SampleRuntimeException.class);
}
}
public void testRunUninterruptiblyWithTimeout_goodRunnableWithEnoughTime() throws Exception {
Stopwatch stopwatch = Stopwatch.createStarted();
service.runUninterruptiblyWithTimeout(GOOD_RUNNABLE, ENOUGH_MS, MILLISECONDS);
assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
}
public void testRunUninterruptiblyWithTimeout_goodRunnableWithNotEnoughTime() throws Exception {
try {
service.runUninterruptiblyWithTimeout(GOOD_RUNNABLE, NOT_ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (TimeoutException expected) {
}
}
public void testRunUninterruptiblyWithTimeout_badRunnableWithEnoughTime() throws Exception {
try {
service.runUninterruptiblyWithTimeout(BAD_RUNNABLE, ENOUGH_MS, MILLISECONDS);
fail("no exception thrown");
} catch (UncheckedExecutionException expected) {
assertThat(expected.getCause()).isInstanceOf(SampleRuntimeException.class);
}
}
private interface Sample {
String sleepThenReturnInput(String input);
void sleepThenThrowException() throws SampleException;
}
@SuppressWarnings("serial")
private static class SampleException extends Exception {}
@SuppressWarnings("serial")
private static class SampleRuntimeException extends RuntimeException {}
private static class SampleImpl implements Sample {
final long delayMillis;
boolean finished;
SampleImpl(long delayMillis) {
this.delayMillis = delayMillis;
}
@Override
public String sleepThenReturnInput(String input) {
try {
MILLISECONDS.sleep(delayMillis);
finished = true;
return input;
} catch (InterruptedException e) {
return null;
}
}
@Override
public void sleepThenThrowException() throws SampleException {
try {
MILLISECONDS.sleep(delayMillis);
} catch (InterruptedException e) {
}
throw new SampleException();
}
}
}