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