• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.util.concurrent;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static java.util.concurrent.TimeUnit.MILLISECONDS;
21 import static org.junit.Assert.assertThrows;
22 
23 import com.google.common.base.Stopwatch;
24 import com.google.common.collect.Range;
25 import java.util.concurrent.Callable;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.TimeoutException;
30 import junit.framework.TestCase;
31 
32 /**
33  * Unit test for {@link SimpleTimeLimiter}.
34  *
35  * @author kevinb
36  * @author Jens Nyman
37  */
38 public class SimpleTimeLimiterTest extends TestCase {
39 
40   private static final long DELAY_MS = 50;
41   private static final long ENOUGH_MS = 10000;
42   private static final long NOT_ENOUGH_MS = 5;
43 
44   private static final String GOOD_CALLABLE_RESULT = "good callable result";
45   private static final Callable<String> GOOD_CALLABLE =
46       new Callable<String>() {
47         @Override
48         public String call() throws InterruptedException {
49           MILLISECONDS.sleep(DELAY_MS);
50           return GOOD_CALLABLE_RESULT;
51         }
52       };
53   private static final Callable<String> BAD_CALLABLE =
54       new Callable<String>() {
55         @Override
56         public String call() throws InterruptedException, SampleException {
57           MILLISECONDS.sleep(DELAY_MS);
58           throw new SampleException();
59         }
60       };
61   private static final Runnable GOOD_RUNNABLE =
62       new Runnable() {
63         @Override
64         public void run() {
65           try {
66             MILLISECONDS.sleep(DELAY_MS);
67           } catch (InterruptedException e) {
68             throw new RuntimeException(e);
69           }
70         }
71       };
72   private static final Runnable BAD_RUNNABLE =
73       new Runnable() {
74         @Override
75         public void run() {
76           try {
77             MILLISECONDS.sleep(DELAY_MS);
78           } catch (InterruptedException e) {
79             throw new RuntimeException(e);
80           }
81           throw new SampleRuntimeException();
82         }
83       };
84 
85   private TimeLimiter service;
86 
87   private static final ExecutorService executor = Executors.newFixedThreadPool(1);
88 
89   @Override
setUp()90   protected void setUp() throws Exception {
91     super.setUp();
92     service = SimpleTimeLimiter.create(executor);
93   }
94 
testNewProxy_goodMethodWithEnoughTime()95   public void testNewProxy_goodMethodWithEnoughTime() throws Exception {
96     SampleImpl target = new SampleImpl(DELAY_MS);
97     Sample proxy = service.newProxy(target, Sample.class, ENOUGH_MS, MILLISECONDS);
98     Stopwatch stopwatch = Stopwatch.createStarted();
99 
100     String result = proxy.sleepThenReturnInput("x");
101 
102     assertThat(result).isEqualTo("x");
103     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
104     assertThat(target.finished).isTrue();
105   }
106 
testNewProxy_goodMethodWithNotEnoughTime()107   public void testNewProxy_goodMethodWithNotEnoughTime() throws Exception {
108     SampleImpl target = new SampleImpl(9999);
109     Sample proxy = service.newProxy(target, Sample.class, NOT_ENOUGH_MS, MILLISECONDS);
110     Stopwatch stopwatch = Stopwatch.createStarted();
111 
112     assertThrows(UncheckedTimeoutException.class, () -> proxy.sleepThenReturnInput("x"));
113 
114     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(NOT_ENOUGH_MS, DELAY_MS * 2));
115     // Is it still computing away anyway?
116     assertThat(target.finished).isFalse();
117     MILLISECONDS.sleep(ENOUGH_MS);
118     assertThat(target.finished).isFalse();
119   }
120 
testNewProxy_badMethodWithEnoughTime()121   public void testNewProxy_badMethodWithEnoughTime() throws Exception {
122     SampleImpl target = new SampleImpl(DELAY_MS);
123     Sample proxy = service.newProxy(target, Sample.class, ENOUGH_MS, MILLISECONDS);
124     Stopwatch stopwatch = Stopwatch.createStarted();
125 
126     assertThrows(SampleException.class, () -> proxy.sleepThenThrowException());
127 
128     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
129   }
130 
testNewProxy_badMethodWithNotEnoughTime()131   public void testNewProxy_badMethodWithNotEnoughTime() throws Exception {
132     SampleImpl target = new SampleImpl(9999);
133     Sample proxy = service.newProxy(target, Sample.class, NOT_ENOUGH_MS, MILLISECONDS);
134     Stopwatch stopwatch = Stopwatch.createStarted();
135 
136     assertThrows(UncheckedTimeoutException.class, () -> proxy.sleepThenThrowException());
137 
138     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(NOT_ENOUGH_MS, DELAY_MS * 2));
139   }
140 
testCallWithTimeout_goodCallableWithEnoughTime()141   public void testCallWithTimeout_goodCallableWithEnoughTime() throws Exception {
142     Stopwatch stopwatch = Stopwatch.createStarted();
143 
144     String result = service.callWithTimeout(GOOD_CALLABLE, ENOUGH_MS, MILLISECONDS);
145 
146     assertThat(result).isEqualTo(GOOD_CALLABLE_RESULT);
147     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
148   }
149 
testCallWithTimeout_goodCallableWithNotEnoughTime()150   public void testCallWithTimeout_goodCallableWithNotEnoughTime() throws Exception {
151     assertThrows(
152         TimeoutException.class,
153         () -> service.callWithTimeout(GOOD_CALLABLE, NOT_ENOUGH_MS, MILLISECONDS));
154   }
155 
testCallWithTimeout_badCallableWithEnoughTime()156   public void testCallWithTimeout_badCallableWithEnoughTime() throws Exception {
157     ExecutionException expected =
158         assertThrows(
159             ExecutionException.class,
160             () -> service.callWithTimeout(BAD_CALLABLE, ENOUGH_MS, MILLISECONDS));
161     assertThat(expected.getCause()).isInstanceOf(SampleException.class);
162   }
163 
testCallUninterruptiblyWithTimeout_goodCallableWithEnoughTime()164   public void testCallUninterruptiblyWithTimeout_goodCallableWithEnoughTime() throws Exception {
165     Stopwatch stopwatch = Stopwatch.createStarted();
166 
167     String result = service.callUninterruptiblyWithTimeout(GOOD_CALLABLE, ENOUGH_MS, MILLISECONDS);
168 
169     assertThat(result).isEqualTo(GOOD_CALLABLE_RESULT);
170     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
171   }
172 
testCallUninterruptiblyWithTimeout_goodCallableWithNotEnoughTime()173   public void testCallUninterruptiblyWithTimeout_goodCallableWithNotEnoughTime() throws Exception {
174     assertThrows(
175         TimeoutException.class,
176         () -> service.callUninterruptiblyWithTimeout(GOOD_CALLABLE, NOT_ENOUGH_MS, MILLISECONDS));
177   }
178 
testCallUninterruptiblyWithTimeout_badCallableWithEnoughTime()179   public void testCallUninterruptiblyWithTimeout_badCallableWithEnoughTime() throws Exception {
180     ExecutionException expected =
181         assertThrows(
182             ExecutionException.class,
183             () -> service.callUninterruptiblyWithTimeout(BAD_CALLABLE, ENOUGH_MS, MILLISECONDS));
184     assertThat(expected.getCause()).isInstanceOf(SampleException.class);
185   }
186 
testRunWithTimeout_goodRunnableWithEnoughTime()187   public void testRunWithTimeout_goodRunnableWithEnoughTime() throws Exception {
188     Stopwatch stopwatch = Stopwatch.createStarted();
189 
190     service.runWithTimeout(GOOD_RUNNABLE, ENOUGH_MS, MILLISECONDS);
191 
192     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
193   }
194 
testRunWithTimeout_goodRunnableWithNotEnoughTime()195   public void testRunWithTimeout_goodRunnableWithNotEnoughTime() throws Exception {
196     assertThrows(
197         TimeoutException.class,
198         () -> service.runWithTimeout(GOOD_RUNNABLE, NOT_ENOUGH_MS, MILLISECONDS));
199   }
200 
testRunWithTimeout_badRunnableWithEnoughTime()201   public void testRunWithTimeout_badRunnableWithEnoughTime() throws Exception {
202     UncheckedExecutionException expected =
203         assertThrows(
204             UncheckedExecutionException.class,
205             () -> service.runWithTimeout(BAD_RUNNABLE, ENOUGH_MS, MILLISECONDS));
206     assertThat(expected.getCause()).isInstanceOf(SampleRuntimeException.class);
207   }
208 
testRunUninterruptiblyWithTimeout_goodRunnableWithEnoughTime()209   public void testRunUninterruptiblyWithTimeout_goodRunnableWithEnoughTime() throws Exception {
210     Stopwatch stopwatch = Stopwatch.createStarted();
211 
212     service.runUninterruptiblyWithTimeout(GOOD_RUNNABLE, ENOUGH_MS, MILLISECONDS);
213 
214     assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS));
215   }
216 
testRunUninterruptiblyWithTimeout_goodRunnableWithNotEnoughTime()217   public void testRunUninterruptiblyWithTimeout_goodRunnableWithNotEnoughTime() throws Exception {
218     assertThrows(
219         TimeoutException.class,
220         () -> service.runUninterruptiblyWithTimeout(GOOD_RUNNABLE, NOT_ENOUGH_MS, MILLISECONDS));
221   }
222 
testRunUninterruptiblyWithTimeout_badRunnableWithEnoughTime()223   public void testRunUninterruptiblyWithTimeout_badRunnableWithEnoughTime() throws Exception {
224     UncheckedExecutionException expected =
225         assertThrows(
226             UncheckedExecutionException.class,
227             () -> service.runUninterruptiblyWithTimeout(BAD_RUNNABLE, ENOUGH_MS, MILLISECONDS));
228     assertThat(expected.getCause()).isInstanceOf(SampleRuntimeException.class);
229   }
230 
231   private interface Sample {
sleepThenReturnInput(String input)232     String sleepThenReturnInput(String input);
233 
sleepThenThrowException()234     void sleepThenThrowException() throws SampleException;
235   }
236 
237   @SuppressWarnings("serial")
238   private static class SampleException extends Exception {}
239 
240   @SuppressWarnings("serial")
241   private static class SampleRuntimeException extends RuntimeException {}
242 
243   private static class SampleImpl implements Sample {
244     final long delayMillis;
245     boolean finished;
246 
SampleImpl(long delayMillis)247     SampleImpl(long delayMillis) {
248       this.delayMillis = delayMillis;
249     }
250 
251     @Override
sleepThenReturnInput(String input)252     public String sleepThenReturnInput(String input) {
253       try {
254         MILLISECONDS.sleep(delayMillis);
255         finished = true;
256         return input;
257       } catch (InterruptedException e) {
258         throw new AssertionError();
259       }
260     }
261 
262     @Override
sleepThenThrowException()263     public void sleepThenThrowException() throws SampleException {
264       try {
265         MILLISECONDS.sleep(delayMillis);
266       } catch (InterruptedException e) {
267       }
268       throw new SampleException();
269     }
270   }
271 }
272