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 junit.framework.TestCase;
20 
21 import java.util.concurrent.Callable;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.TimeUnit;
25 
26 /**
27  * Unit test for {@link SimpleTimeLimiter}.
28  *
29  * @author kevinb
30  */
31 public class SimpleTimeLimiterTest extends TestCase {
32 
33   private static final int DELAY_MS = 50;
34   private static final int ENOUGH_MS = 500;
35   private static final int NOT_ENOUGH_MS = 5;
36 
37   private TimeLimiter service;
38 
39   private static final ExecutorService executor
40       = Executors.newFixedThreadPool(1);
41 
someGoodStaticMethod()42   private static String someGoodStaticMethod() throws InterruptedException {
43     TimeUnit.MILLISECONDS.sleep(DELAY_MS);
44     return "yes";
45   }
46 
someBadStaticMethod()47   private static String someBadStaticMethod() throws InterruptedException,
48       SampleException {
49     TimeUnit.MILLISECONDS.sleep(DELAY_MS);
50     throw new SampleException();
51   }
52 
setUp()53   @Override protected void setUp() throws Exception {
54     super.setUp();
55     service = new SimpleTimeLimiter(executor);
56   }
57 
testGoodCallableWithEnoughTime()58   public void testGoodCallableWithEnoughTime() throws Exception {
59     long start = System.nanoTime();
60     String result = service.callWithTimeout(
61         new Callable<String>() {
62           @Override
63           public String call() throws InterruptedException {
64             return someGoodStaticMethod();
65           }
66         }, ENOUGH_MS, TimeUnit.MILLISECONDS, true);
67     assertEquals("yes", result);
68     assertTheCallTookBetween(start, DELAY_MS, ENOUGH_MS);
69   }
70 
testGoodCallableWithNotEnoughTime()71   public void testGoodCallableWithNotEnoughTime() throws Exception {
72     long start = System.nanoTime();
73     try {
74       service.callWithTimeout(
75           new Callable<String>() {
76             @Override
77             public String call() throws InterruptedException {
78               return someGoodStaticMethod();
79             }
80           }, NOT_ENOUGH_MS, TimeUnit.MILLISECONDS, true);
81       fail("no exception thrown");
82     } catch (UncheckedTimeoutException expected) {
83     }
84     assertTheCallTookBetween(start, NOT_ENOUGH_MS, DELAY_MS);
85   }
86 
testBadCallableWithEnoughTime()87   public void testBadCallableWithEnoughTime() throws Exception {
88     long start = System.nanoTime();
89     try {
90       service.callWithTimeout(
91           new Callable<String>() {
92             @Override
93             public String call() throws SampleException, InterruptedException {
94               return someBadStaticMethod();
95             }
96           }, ENOUGH_MS, TimeUnit.MILLISECONDS, true);
97       fail("no exception thrown");
98     } catch (SampleException expected) {
99     }
100     assertTheCallTookBetween(start, DELAY_MS, ENOUGH_MS);
101   }
102 
testBadCallableWithNotEnoughTime()103   public void testBadCallableWithNotEnoughTime() throws Exception {
104     long start = System.nanoTime();
105     try {
106       service.callWithTimeout(
107           new Callable<String>() {
108             @Override
109             public String call() throws SampleException, InterruptedException {
110               return someBadStaticMethod();
111             }
112           }, NOT_ENOUGH_MS, TimeUnit.MILLISECONDS, true);
113       fail("no exception thrown");
114     } catch (UncheckedTimeoutException expected) {
115     }
116     assertTheCallTookBetween(start, NOT_ENOUGH_MS, DELAY_MS);
117   }
118 
testGoodMethodWithEnoughTime()119   public void testGoodMethodWithEnoughTime() throws Exception {
120     SampleImpl target = new SampleImpl();
121     Sample proxy = service.newProxy(
122         target, Sample.class, ENOUGH_MS, TimeUnit.MILLISECONDS);
123     long start = System.nanoTime();
124     assertEquals("x", proxy.sleepThenReturnInput("x"));
125     assertTheCallTookBetween(start, DELAY_MS, ENOUGH_MS);
126     assertTrue(target.finished);
127   }
128 
testGoodMethodWithNotEnoughTime()129   public void testGoodMethodWithNotEnoughTime() throws Exception {
130     SampleImpl target = new SampleImpl();
131     Sample proxy = service.newProxy(
132         target, Sample.class, NOT_ENOUGH_MS, TimeUnit.MILLISECONDS);
133     long start = System.nanoTime();
134     try {
135       proxy.sleepThenReturnInput("x");
136       fail("no exception thrown");
137     } catch (UncheckedTimeoutException expected) {
138     }
139     assertTheCallTookBetween(start, NOT_ENOUGH_MS, DELAY_MS);
140 
141     // Is it still computing away anyway?
142     assertFalse(target.finished);
143     TimeUnit.MILLISECONDS.sleep(ENOUGH_MS);
144     assertFalse(target.finished);
145   }
146 
testBadMethodWithEnoughTime()147   public void testBadMethodWithEnoughTime() throws Exception {
148     SampleImpl target = new SampleImpl();
149     Sample proxy = service.newProxy(
150         target, Sample.class, ENOUGH_MS, TimeUnit.MILLISECONDS);
151     long start = System.nanoTime();
152     try {
153       proxy.sleepThenThrowException();
154       fail("no exception thrown");
155     } catch (SampleException expected) {
156     }
157     assertTheCallTookBetween(start, DELAY_MS, ENOUGH_MS);
158   }
159 
testBadMethodWithNotEnoughTime()160   public void testBadMethodWithNotEnoughTime() throws Exception {
161     SampleImpl target = new SampleImpl();
162     Sample proxy = service.newProxy(
163         target, Sample.class, NOT_ENOUGH_MS, TimeUnit.MILLISECONDS);
164     long start = System.nanoTime();
165     try {
166       proxy.sleepThenThrowException();
167       fail("no exception thrown");
168     } catch (UncheckedTimeoutException expected) {
169     }
170     assertTheCallTookBetween(start, NOT_ENOUGH_MS, DELAY_MS);
171   }
172 
assertTheCallTookBetween( long startNanos, int atLeastMillis, int atMostMillis)173   private static void assertTheCallTookBetween(
174       long startNanos, int atLeastMillis, int atMostMillis) {
175     long nanos = System.nanoTime() - startNanos;
176     assertTrue(nanos >= atLeastMillis * 1000000);
177     assertTrue(nanos <= atMostMillis * 1000000);
178   }
179 
180   public interface Sample {
sleepThenReturnInput(String input)181     String sleepThenReturnInput(String input);
sleepThenThrowException()182     void sleepThenThrowException() throws SampleException;
183   }
184 
185   @SuppressWarnings("serial")
186   public static class SampleException extends Exception {}
187 
188   public static class SampleImpl implements Sample {
189     boolean finished;
190 
191     @Override
sleepThenReturnInput(String input)192     public String sleepThenReturnInput(String input) {
193       try {
194         TimeUnit.MILLISECONDS.sleep(DELAY_MS);
195         finished = true;
196         return input;
197       } catch (InterruptedException e) {
198         return null;
199       }
200     }
201     @Override
sleepThenThrowException()202     public void sleepThenThrowException() throws SampleException {
203       try {
204         TimeUnit.MILLISECONDS.sleep(DELAY_MS);
205       } catch (InterruptedException e) {
206       }
207       throw new SampleException();
208     }
209   }
210 }
211