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 22 import com.google.common.base.Stopwatch; 23 import com.google.common.collect.Range; 24 import java.util.concurrent.Callable; 25 import java.util.concurrent.ExecutionException; 26 import java.util.concurrent.ExecutorService; 27 import java.util.concurrent.Executors; 28 import java.util.concurrent.TimeoutException; 29 import junit.framework.TestCase; 30 31 /** 32 * Unit test for {@link SimpleTimeLimiter}. 33 * 34 * @author kevinb 35 * @author Jens Nyman 36 */ 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 try { 113 proxy.sleepThenReturnInput("x"); 114 fail("no exception thrown"); 115 } catch (UncheckedTimeoutException expected) { 116 } 117 118 assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(NOT_ENOUGH_MS, DELAY_MS * 2)); 119 // Is it still computing away anyway? 120 assertThat(target.finished).isFalse(); 121 MILLISECONDS.sleep(ENOUGH_MS); 122 assertThat(target.finished).isFalse(); 123 } 124 testNewProxy_badMethodWithEnoughTime()125 public void testNewProxy_badMethodWithEnoughTime() throws Exception { 126 SampleImpl target = new SampleImpl(DELAY_MS); 127 Sample proxy = service.newProxy(target, Sample.class, ENOUGH_MS, MILLISECONDS); 128 Stopwatch stopwatch = Stopwatch.createStarted(); 129 130 try { 131 proxy.sleepThenThrowException(); 132 fail("no exception thrown"); 133 } catch (SampleException expected) { 134 } 135 136 assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS)); 137 } 138 testNewProxy_badMethodWithNotEnoughTime()139 public void testNewProxy_badMethodWithNotEnoughTime() throws Exception { 140 SampleImpl target = new SampleImpl(9999); 141 Sample proxy = service.newProxy(target, Sample.class, NOT_ENOUGH_MS, MILLISECONDS); 142 Stopwatch stopwatch = Stopwatch.createStarted(); 143 144 try { 145 proxy.sleepThenThrowException(); 146 fail("no exception thrown"); 147 } catch (UncheckedTimeoutException expected) { 148 } 149 150 assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(NOT_ENOUGH_MS, DELAY_MS * 2)); 151 } 152 testCallWithTimeout_goodCallableWithEnoughTime()153 public void testCallWithTimeout_goodCallableWithEnoughTime() throws Exception { 154 Stopwatch stopwatch = Stopwatch.createStarted(); 155 156 String result = service.callWithTimeout(GOOD_CALLABLE, ENOUGH_MS, MILLISECONDS); 157 158 assertThat(result).isEqualTo(GOOD_CALLABLE_RESULT); 159 assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS)); 160 } 161 testCallWithTimeout_goodCallableWithNotEnoughTime()162 public void testCallWithTimeout_goodCallableWithNotEnoughTime() throws Exception { 163 try { 164 service.callWithTimeout(GOOD_CALLABLE, NOT_ENOUGH_MS, MILLISECONDS); 165 fail("no exception thrown"); 166 } catch (TimeoutException expected) { 167 } 168 } 169 testCallWithTimeout_badCallableWithEnoughTime()170 public void testCallWithTimeout_badCallableWithEnoughTime() throws Exception { 171 try { 172 service.callWithTimeout(BAD_CALLABLE, ENOUGH_MS, MILLISECONDS); 173 fail("no exception thrown"); 174 } catch (ExecutionException expected) { 175 assertThat(expected.getCause()).isInstanceOf(SampleException.class); 176 } 177 } 178 testCallUninterruptiblyWithTimeout_goodCallableWithEnoughTime()179 public void testCallUninterruptiblyWithTimeout_goodCallableWithEnoughTime() throws Exception { 180 Stopwatch stopwatch = Stopwatch.createStarted(); 181 182 String result = service.callUninterruptiblyWithTimeout(GOOD_CALLABLE, ENOUGH_MS, MILLISECONDS); 183 184 assertThat(result).isEqualTo(GOOD_CALLABLE_RESULT); 185 assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS)); 186 } 187 testCallUninterruptiblyWithTimeout_goodCallableWithNotEnoughTime()188 public void testCallUninterruptiblyWithTimeout_goodCallableWithNotEnoughTime() throws Exception { 189 try { 190 service.callUninterruptiblyWithTimeout(GOOD_CALLABLE, NOT_ENOUGH_MS, MILLISECONDS); 191 fail("no exception thrown"); 192 } catch (TimeoutException expected) { 193 } 194 } 195 testCallUninterruptiblyWithTimeout_badCallableWithEnoughTime()196 public void testCallUninterruptiblyWithTimeout_badCallableWithEnoughTime() throws Exception { 197 try { 198 service.callUninterruptiblyWithTimeout(BAD_CALLABLE, ENOUGH_MS, MILLISECONDS); 199 fail("no exception thrown"); 200 } catch (ExecutionException expected) { 201 assertThat(expected.getCause()).isInstanceOf(SampleException.class); 202 } 203 } 204 testRunWithTimeout_goodRunnableWithEnoughTime()205 public void testRunWithTimeout_goodRunnableWithEnoughTime() throws Exception { 206 Stopwatch stopwatch = Stopwatch.createStarted(); 207 208 service.runWithTimeout(GOOD_RUNNABLE, ENOUGH_MS, MILLISECONDS); 209 210 assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS)); 211 } 212 testRunWithTimeout_goodRunnableWithNotEnoughTime()213 public void testRunWithTimeout_goodRunnableWithNotEnoughTime() throws Exception { 214 try { 215 service.runWithTimeout(GOOD_RUNNABLE, NOT_ENOUGH_MS, MILLISECONDS); 216 fail("no exception thrown"); 217 } catch (TimeoutException expected) { 218 } 219 } 220 testRunWithTimeout_badRunnableWithEnoughTime()221 public void testRunWithTimeout_badRunnableWithEnoughTime() throws Exception { 222 try { 223 service.runWithTimeout(BAD_RUNNABLE, ENOUGH_MS, MILLISECONDS); 224 fail("no exception thrown"); 225 } catch (UncheckedExecutionException expected) { 226 assertThat(expected.getCause()).isInstanceOf(SampleRuntimeException.class); 227 } 228 } 229 testRunUninterruptiblyWithTimeout_goodRunnableWithEnoughTime()230 public void testRunUninterruptiblyWithTimeout_goodRunnableWithEnoughTime() throws Exception { 231 Stopwatch stopwatch = Stopwatch.createStarted(); 232 233 service.runUninterruptiblyWithTimeout(GOOD_RUNNABLE, ENOUGH_MS, MILLISECONDS); 234 235 assertThat(stopwatch.elapsed(MILLISECONDS)).isIn(Range.closed(DELAY_MS, ENOUGH_MS)); 236 } 237 testRunUninterruptiblyWithTimeout_goodRunnableWithNotEnoughTime()238 public void testRunUninterruptiblyWithTimeout_goodRunnableWithNotEnoughTime() throws Exception { 239 try { 240 service.runUninterruptiblyWithTimeout(GOOD_RUNNABLE, NOT_ENOUGH_MS, MILLISECONDS); 241 fail("no exception thrown"); 242 } catch (TimeoutException expected) { 243 } 244 } 245 testRunUninterruptiblyWithTimeout_badRunnableWithEnoughTime()246 public void testRunUninterruptiblyWithTimeout_badRunnableWithEnoughTime() throws Exception { 247 try { 248 service.runUninterruptiblyWithTimeout(BAD_RUNNABLE, ENOUGH_MS, MILLISECONDS); 249 fail("no exception thrown"); 250 } catch (UncheckedExecutionException expected) { 251 assertThat(expected.getCause()).isInstanceOf(SampleRuntimeException.class); 252 } 253 } 254 255 private interface Sample { sleepThenReturnInput(String input)256 String sleepThenReturnInput(String input); 257 sleepThenThrowException()258 void sleepThenThrowException() throws SampleException; 259 } 260 261 @SuppressWarnings("serial") 262 private static class SampleException extends Exception {} 263 264 @SuppressWarnings("serial") 265 private static class SampleRuntimeException extends RuntimeException {} 266 267 private static class SampleImpl implements Sample { 268 final long delayMillis; 269 boolean finished; 270 SampleImpl(long delayMillis)271 SampleImpl(long delayMillis) { 272 this.delayMillis = delayMillis; 273 } 274 275 @Override sleepThenReturnInput(String input)276 public String sleepThenReturnInput(String input) { 277 try { 278 MILLISECONDS.sleep(delayMillis); 279 finished = true; 280 return input; 281 } catch (InterruptedException e) { 282 return null; 283 } 284 } 285 286 @Override sleepThenThrowException()287 public void sleepThenThrowException() throws SampleException { 288 try { 289 MILLISECONDS.sleep(delayMillis); 290 } catch (InterruptedException e) { 291 } 292 throw new SampleException(); 293 } 294 } 295 } 296