| /* |
| * 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(); |
| } |
| } |
| } |