• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 java.lang.reflect.Modifier.isStatic;
20 import static java.util.concurrent.TimeUnit.MICROSECONDS;
21 import static java.util.concurrent.TimeUnit.MILLISECONDS;
22 import static java.util.concurrent.TimeUnit.NANOSECONDS;
23 import static java.util.concurrent.TimeUnit.SECONDS;
24 
25 import com.google.common.collect.ImmutableClassToInstanceMap;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.collect.Lists;
28 import com.google.common.testing.NullPointerTester;
29 import com.google.common.testing.NullPointerTester.Visibility;
30 import com.google.common.util.concurrent.RateLimiter.SleepingStopwatch;
31 import java.lang.reflect.Method;
32 import java.util.Arrays;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Random;
36 import java.util.concurrent.TimeUnit;
37 import junit.framework.TestCase;
38 import org.easymock.EasyMock;
39 import org.mockito.Mockito;
40 
41 /**
42  * Tests for RateLimiter.
43  *
44  * @author Dimitris Andreou
45  */
46 public class RateLimiterTest extends TestCase {
47   private static final double EPSILON = 1e-8;
48 
49   private final FakeStopwatch stopwatch = new FakeStopwatch();
50 
testSimple()51   public void testSimple() {
52     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
53     limiter.acquire(); // R0.00, since it's the first request
54     limiter.acquire(); // R0.20
55     limiter.acquire(); // R0.20
56     assertEvents("R0.00", "R0.20", "R0.20");
57   }
58 
testImmediateTryAcquire()59   public void testImmediateTryAcquire() {
60     RateLimiter r = RateLimiter.create(1);
61     assertTrue("Unable to acquire initial permit", r.tryAcquire());
62     assertFalse("Capable of acquiring secondary permit", r.tryAcquire());
63   }
64 
testDoubleMinValueCanAcquireExactlyOnce()65   public void testDoubleMinValueCanAcquireExactlyOnce() {
66     RateLimiter r = RateLimiter.create(Double.MIN_VALUE, stopwatch);
67     assertTrue("Unable to acquire initial permit", r.tryAcquire());
68     assertFalse("Capable of acquiring an additional permit", r.tryAcquire());
69     stopwatch.sleepMillis(Integer.MAX_VALUE);
70     assertFalse("Capable of acquiring an additional permit after sleeping", r.tryAcquire());
71   }
72 
testSimpleRateUpdate()73   public void testSimpleRateUpdate() {
74     RateLimiter limiter = RateLimiter.create(5.0, 5, SECONDS);
75     assertEquals(5.0, limiter.getRate());
76     limiter.setRate(10.0);
77     assertEquals(10.0, limiter.getRate());
78 
79     try {
80       limiter.setRate(0.0);
81       fail();
82     } catch (IllegalArgumentException expected) {
83     }
84     try {
85       limiter.setRate(-10.0);
86       fail();
87     } catch (IllegalArgumentException expected) {
88     }
89   }
90 
testAcquireParameterValidation()91   public void testAcquireParameterValidation() {
92     RateLimiter limiter = RateLimiter.create(999);
93     try {
94       limiter.acquire(0);
95       fail();
96     } catch (IllegalArgumentException expected) {
97     }
98     try {
99       limiter.acquire(-1);
100       fail();
101     } catch (IllegalArgumentException expected) {
102     }
103     try {
104       limiter.tryAcquire(0);
105       fail();
106     } catch (IllegalArgumentException expected) {
107     }
108     try {
109       limiter.tryAcquire(-1);
110       fail();
111     } catch (IllegalArgumentException expected) {
112     }
113     try {
114       limiter.tryAcquire(0, 1, SECONDS);
115       fail();
116     } catch (IllegalArgumentException expected) {
117     }
118     try {
119       limiter.tryAcquire(-1, 1, SECONDS);
120       fail();
121     } catch (IllegalArgumentException expected) {
122     }
123   }
124 
testSimpleWithWait()125   public void testSimpleWithWait() {
126     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
127     limiter.acquire(); // R0.00
128     stopwatch.sleepMillis(200); // U0.20, we are ready for the next request...
129     limiter.acquire(); // R0.00, ...which is granted immediately
130     limiter.acquire(); // R0.20
131     assertEvents("R0.00", "U0.20", "R0.00", "R0.20");
132   }
133 
testSimpleAcquireReturnValues()134   public void testSimpleAcquireReturnValues() {
135     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
136     assertEquals(0.0, limiter.acquire(), EPSILON); // R0.00
137     stopwatch.sleepMillis(200); // U0.20, we are ready for the next request...
138     assertEquals(0.0, limiter.acquire(), EPSILON); // R0.00, ...which is granted immediately
139     assertEquals(0.2, limiter.acquire(), EPSILON); // R0.20
140     assertEvents("R0.00", "U0.20", "R0.00", "R0.20");
141   }
142 
testSimpleAcquireEarliestAvailableIsInPast()143   public void testSimpleAcquireEarliestAvailableIsInPast() {
144     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
145     assertEquals(0.0, limiter.acquire(), EPSILON);
146     stopwatch.sleepMillis(400);
147     assertEquals(0.0, limiter.acquire(), EPSILON);
148     assertEquals(0.0, limiter.acquire(), EPSILON);
149     assertEquals(0.2, limiter.acquire(), EPSILON);
150   }
151 
testOneSecondBurst()152   public void testOneSecondBurst() {
153     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
154     stopwatch.sleepMillis(1000); // max capacity reached
155     stopwatch.sleepMillis(1000); // this makes no difference
156     limiter.acquire(1); // R0.00, since it's the first request
157 
158     limiter.acquire(1); // R0.00, from capacity
159     limiter.acquire(3); // R0.00, from capacity
160     limiter.acquire(1); // R0.00, concluding a burst of 5 permits
161 
162     limiter.acquire(); // R0.20, capacity exhausted
163     assertEvents(
164         "U1.00", "U1.00", "R0.00", "R0.00", "R0.00", "R0.00", // first request and burst
165         "R0.20");
166   }
167 
testCreateWarmupParameterValidation()168   public void testCreateWarmupParameterValidation() {
169     RateLimiter unused;
170     unused = RateLimiter.create(1.0, 1, NANOSECONDS);
171     unused = RateLimiter.create(1.0, 0, NANOSECONDS);
172 
173     try {
174       RateLimiter.create(0.0, 1, NANOSECONDS);
175       fail();
176     } catch (IllegalArgumentException expected) {
177     }
178 
179     try {
180       RateLimiter.create(1.0, -1, NANOSECONDS);
181       fail();
182     } catch (IllegalArgumentException expected) {
183     }
184   }
185 
186   @AndroidIncompatible // difference in String.format rounding?
testWarmUp()187   public void testWarmUp() {
188     RateLimiter limiter = RateLimiter.create(2.0, 4000, MILLISECONDS, 3.0, stopwatch);
189     for (int i = 0; i < 8; i++) {
190       limiter.acquire(); // #1
191     }
192     stopwatch.sleepMillis(500); // #2: to repay for the last acquire
193     stopwatch.sleepMillis(4000); // #3: becomes cold again
194     for (int i = 0; i < 8; i++) {
195       limiter.acquire(); // // #4
196     }
197     stopwatch.sleepMillis(500); // #5: to repay for the last acquire
198     stopwatch.sleepMillis(2000); // #6: didn't get cold! It would take another 2 seconds to go cold
199     for (int i = 0; i < 8; i++) {
200       limiter.acquire(); // #7
201     }
202     assertEvents(
203         "R0.00, R1.38, R1.13, R0.88, R0.63, R0.50, R0.50, R0.50", // #1
204         "U0.50", // #2
205         "U4.00", // #3
206         "R0.00, R1.38, R1.13, R0.88, R0.63, R0.50, R0.50, R0.50", // #4
207         "U0.50", // #5
208         "U2.00", // #6
209         "R0.00, R0.50, R0.50, R0.50, R0.50, R0.50, R0.50, R0.50"); // #7
210   }
211 
testWarmUpWithColdFactor()212   public void testWarmUpWithColdFactor() {
213     RateLimiter limiter = RateLimiter.create(5.0, 4000, MILLISECONDS, 10.0, stopwatch);
214     for (int i = 0; i < 8; i++) {
215       limiter.acquire(); // #1
216     }
217     stopwatch.sleepMillis(200); // #2: to repay for the last acquire
218     stopwatch.sleepMillis(4000); // #3: becomes cold again
219     for (int i = 0; i < 8; i++) {
220       limiter.acquire(); // // #4
221     }
222     stopwatch.sleepMillis(200); // #5: to repay for the last acquire
223     stopwatch.sleepMillis(1000); // #6: still warm! It would take another 3 seconds to go cold
224     for (int i = 0; i < 8; i++) {
225       limiter.acquire(); // #7
226     }
227     assertEvents(
228         "R0.00, R1.75, R1.26, R0.76, R0.30, R0.20, R0.20, R0.20", // #1
229         "U0.20", // #2
230         "U4.00", // #3
231         "R0.00, R1.75, R1.26, R0.76, R0.30, R0.20, R0.20, R0.20", // #4
232         "U0.20", // #5
233         "U1.00", // #6
234         "R0.00, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20"); // #7
235   }
236 
testWarmUpWithColdFactor1()237   public void testWarmUpWithColdFactor1() {
238     RateLimiter limiter = RateLimiter.create(5.0, 4000, MILLISECONDS, 1.0, stopwatch);
239     for (int i = 0; i < 8; i++) {
240       limiter.acquire(); // #1
241     }
242     stopwatch.sleepMillis(340); // #2
243     for (int i = 0; i < 8; i++) {
244       limiter.acquire(); // #3
245     }
246     assertEvents(
247         "R0.00, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20", // #1
248         "U0.34", // #2
249         "R0.00, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20"); // #3
250   }
251 
252   @AndroidIncompatible // difference in String.format rounding?
testWarmUpAndUpdate()253   public void testWarmUpAndUpdate() {
254     RateLimiter limiter = RateLimiter.create(2.0, 4000, MILLISECONDS, 3.0, stopwatch);
255     for (int i = 0; i < 8; i++) {
256       limiter.acquire(); // // #1
257     }
258     stopwatch.sleepMillis(4500); // #2: back to cold state (warmup period + repay last acquire)
259     for (int i = 0; i < 3; i++) { // only three steps, we're somewhere in the warmup period
260       limiter.acquire(); // #3
261     }
262 
263     limiter.setRate(4.0); // double the rate!
264     limiter.acquire(); // #4, we repay the debt of the last acquire (imposed by the old rate)
265     for (int i = 0; i < 4; i++) {
266       limiter.acquire(); // #5
267     }
268     stopwatch.sleepMillis(4250); // #6, back to cold state (warmup period + repay last acquire)
269     for (int i = 0; i < 11; i++) {
270       limiter.acquire(); // #7, showing off the warmup starting from totally cold
271     }
272 
273     // make sure the areas (times) remain the same, while permits are different
274     assertEvents(
275         "R0.00, R1.38, R1.13, R0.88, R0.63, R0.50, R0.50, R0.50", // #1
276         "U4.50", // #2
277         "R0.00, R1.38, R1.13", // #3, after that the rate changes
278         "R0.88", // #4, this is what the throttling would be with the old rate
279         "R0.34, R0.28, R0.25, R0.25", // #5
280         "U4.25", // #6
281         "R0.00, R0.72, R0.66, R0.59, R0.53, R0.47, R0.41", // #7
282         "R0.34, R0.28, R0.25, R0.25"); // #7 (cont.), note, this matches #5
283   }
284 
testWarmUpAndUpdateWithColdFactor()285   public void testWarmUpAndUpdateWithColdFactor() {
286     RateLimiter limiter = RateLimiter.create(5.0, 4000, MILLISECONDS, 10.0, stopwatch);
287     for (int i = 0; i < 8; i++) {
288       limiter.acquire(); // #1
289     }
290     stopwatch.sleepMillis(4200); // #2: back to cold state (warmup period + repay last acquire)
291     for (int i = 0; i < 3; i++) { // only three steps, we're somewhere in the warmup period
292       limiter.acquire(); // #3
293     }
294 
295     limiter.setRate(10.0); // double the rate!
296     limiter.acquire(); // #4, we repay the debt of the last acquire (imposed by the old rate)
297     for (int i = 0; i < 4; i++) {
298       limiter.acquire(); // #5
299     }
300     stopwatch.sleepMillis(4100); // #6, back to cold state (warmup period + repay last acquire)
301     for (int i = 0; i < 11; i++) {
302       limiter.acquire(); // #7, showing off the warmup starting from totally cold
303     }
304 
305     // make sure the areas (times) remain the same, while permits are different
306     assertEvents(
307         "R0.00, R1.75, R1.26, R0.76, R0.30, R0.20, R0.20, R0.20", // #1
308         "U4.20", // #2
309         "R0.00, R1.75, R1.26", // #3, after that the rate changes
310         "R0.76", // #4, this is what the throttling would be with the old rate
311         "R0.20, R0.10, R0.10, R0.10", // #5
312         "U4.10", // #6
313         "R0.00, R0.94, R0.81, R0.69, R0.57, R0.44, R0.32", // #7
314         "R0.20, R0.10, R0.10, R0.10"); // #7 (cont.), note, this matches #5
315   }
316 
testBurstyAndUpdate()317   public void testBurstyAndUpdate() {
318     RateLimiter rateLimiter = RateLimiter.create(1.0, stopwatch);
319     rateLimiter.acquire(1); // no wait
320     rateLimiter.acquire(1); // R1.00, to repay previous
321 
322     rateLimiter.setRate(2.0); // update the rate!
323 
324     rateLimiter.acquire(1); // R1.00, to repay previous (the previous was under the old rate!)
325     rateLimiter.acquire(2); // R0.50, to repay previous (now the rate takes effect)
326     rateLimiter.acquire(4); // R1.00, to repay previous
327     rateLimiter.acquire(1); // R2.00, to repay previous
328     assertEvents("R0.00", "R1.00", "R1.00", "R0.50", "R1.00", "R2.00");
329   }
330 
testTryAcquire_noWaitAllowed()331   public void testTryAcquire_noWaitAllowed() {
332     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
333     assertTrue(limiter.tryAcquire(0, SECONDS));
334     assertFalse(limiter.tryAcquire(0, SECONDS));
335     assertFalse(limiter.tryAcquire(0, SECONDS));
336     stopwatch.sleepMillis(100);
337     assertFalse(limiter.tryAcquire(0, SECONDS));
338   }
339 
testTryAcquire_someWaitAllowed()340   public void testTryAcquire_someWaitAllowed() {
341     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
342     assertTrue(limiter.tryAcquire(0, SECONDS));
343     assertTrue(limiter.tryAcquire(200, MILLISECONDS));
344     assertFalse(limiter.tryAcquire(100, MILLISECONDS));
345     stopwatch.sleepMillis(100);
346     assertTrue(limiter.tryAcquire(100, MILLISECONDS));
347   }
348 
testTryAcquire_overflow()349   public void testTryAcquire_overflow() {
350     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
351     assertTrue(limiter.tryAcquire(0, MICROSECONDS));
352     stopwatch.sleepMillis(100);
353     assertTrue(limiter.tryAcquire(Long.MAX_VALUE, MICROSECONDS));
354   }
355 
testTryAcquire_negative()356   public void testTryAcquire_negative() {
357     RateLimiter limiter = RateLimiter.create(5.0, stopwatch);
358     assertTrue(limiter.tryAcquire(5, 0, SECONDS));
359     stopwatch.sleepMillis(900);
360     assertFalse(limiter.tryAcquire(1, Long.MIN_VALUE, SECONDS));
361     stopwatch.sleepMillis(100);
362     assertTrue(limiter.tryAcquire(1, -1, SECONDS));
363   }
364 
testSimpleWeights()365   public void testSimpleWeights() {
366     RateLimiter rateLimiter = RateLimiter.create(1.0, stopwatch);
367     rateLimiter.acquire(1); // no wait
368     rateLimiter.acquire(1); // R1.00, to repay previous
369     rateLimiter.acquire(2); // R1.00, to repay previous
370     rateLimiter.acquire(4); // R2.00, to repay previous
371     rateLimiter.acquire(8); // R4.00, to repay previous
372     rateLimiter.acquire(1); // R8.00, to repay previous
373     assertEvents("R0.00", "R1.00", "R1.00", "R2.00", "R4.00", "R8.00");
374   }
375 
testInfinity_Bursty()376   public void testInfinity_Bursty() {
377     RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, stopwatch);
378     limiter.acquire(Integer.MAX_VALUE / 4);
379     limiter.acquire(Integer.MAX_VALUE / 2);
380     limiter.acquire(Integer.MAX_VALUE);
381     assertEvents("R0.00", "R0.00", "R0.00"); // no wait, infinite rate!
382 
383     limiter.setRate(2.0);
384     limiter.acquire();
385     limiter.acquire();
386     limiter.acquire();
387     limiter.acquire();
388     limiter.acquire();
389     assertEvents(
390         "R0.00", // First comes the saved-up burst, which defaults to a 1-second burst (2 requests).
391         "R0.00", "R0.00", // Now comes the free request.
392         "R0.50", // Now it's 0.5 seconds per request.
393         "R0.50");
394 
395     limiter.setRate(Double.POSITIVE_INFINITY);
396     limiter.acquire();
397     limiter.acquire();
398     limiter.acquire();
399     assertEvents("R0.50", "R0.00", "R0.00"); // we repay the last request (.5sec), then back to +oo
400   }
401 
402   /** https://code.google.com/p/guava-libraries/issues/detail?id=1791 */
testInfinity_BustyTimeElapsed()403   public void testInfinity_BustyTimeElapsed() {
404     RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, stopwatch);
405     stopwatch.instant += 1000000;
406     limiter.setRate(2.0);
407     for (int i = 0; i < 5; i++) {
408       limiter.acquire();
409     }
410     assertEvents(
411         "R0.00", // First comes the saved-up burst, which defaults to a 1-second burst (2 requests).
412         "R0.00", "R0.00", // Now comes the free request.
413         "R0.50", // Now it's 0.5 seconds per request.
414         "R0.50");
415   }
416 
testInfinity_WarmUp()417   public void testInfinity_WarmUp() {
418     RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, 10, SECONDS, 3.0, stopwatch);
419     limiter.acquire(Integer.MAX_VALUE / 4);
420     limiter.acquire(Integer.MAX_VALUE / 2);
421     limiter.acquire(Integer.MAX_VALUE);
422     assertEvents("R0.00", "R0.00", "R0.00");
423 
424     limiter.setRate(1.0);
425     limiter.acquire();
426     limiter.acquire();
427     limiter.acquire();
428     assertEvents("R0.00", "R1.00", "R1.00");
429 
430     limiter.setRate(Double.POSITIVE_INFINITY);
431     limiter.acquire();
432     limiter.acquire();
433     limiter.acquire();
434     assertEvents("R1.00", "R0.00", "R0.00");
435   }
436 
testInfinity_WarmUpTimeElapsed()437   public void testInfinity_WarmUpTimeElapsed() {
438     RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, 10, SECONDS, 3.0, stopwatch);
439     stopwatch.instant += 1000000;
440     limiter.setRate(1.0);
441     for (int i = 0; i < 5; i++) {
442       limiter.acquire();
443     }
444     assertEvents("R0.00", "R1.00", "R1.00", "R1.00", "R1.00");
445   }
446 
447   /**
448    * Make sure that bursts can never go above 1-second-worth-of-work for the current rate, even when
449    * we change the rate.
450    */
testWeNeverGetABurstMoreThanOneSec()451   public void testWeNeverGetABurstMoreThanOneSec() {
452     RateLimiter limiter = RateLimiter.create(1.0, stopwatch);
453     int[] rates = {1000, 1, 10, 1000000, 10, 1};
454     for (int rate : rates) {
455       int oneSecWorthOfWork = rate;
456       stopwatch.sleepMillis(rate * 1000);
457       limiter.setRate(rate);
458       long burst = measureTotalTimeMillis(limiter, oneSecWorthOfWork, new Random());
459       // we allow one second worth of work to go in a burst (i.e. take less than a second)
460       assertTrue(burst <= 1000);
461       long afterBurst = measureTotalTimeMillis(limiter, oneSecWorthOfWork, new Random());
462       // but work beyond that must take at least one second
463       assertTrue(afterBurst >= 1000);
464     }
465   }
466 
467   /**
468    * This neat test shows that no matter what weights we use in our requests, if we push X amount of
469    * permits in a cool state, where X = rate * timeToCoolDown, and we have specified a
470    * timeToWarmUp() period, it will cost as the prescribed amount of time. E.g., calling
471    * [acquire(5), acquire(1)] takes exactly the same time as [acquire(2), acquire(3), acquire(1)].
472    */
testTimeToWarmUpIsHonouredEvenWithWeights()473   public void testTimeToWarmUpIsHonouredEvenWithWeights() {
474     Random random = new Random();
475     int warmupPermits = 10;
476     double[] coldFactorsToTest = {2.0, 3.0, 10.0};
477     double[] qpsToTest = {4.0, 2.0, 1.0, 0.5, 0.1};
478     for (int trial = 0; trial < 100; trial++) {
479       for (double coldFactor : coldFactorsToTest) {
480         for (double qps : qpsToTest) {
481           // If warmupPermits = maxPermits - thresholdPermits then
482           // warmupPeriod = (1 + coldFactor) * warmupPermits * stableInterval / 2
483           long warmupMillis = (long) ((1 + coldFactor) * warmupPermits / (2.0 * qps) * 1000.0);
484           RateLimiter rateLimiter =
485               RateLimiter.create(qps, warmupMillis, MILLISECONDS, coldFactor, stopwatch);
486           assertEquals(warmupMillis, measureTotalTimeMillis(rateLimiter, warmupPermits, random));
487         }
488       }
489     }
490   }
491 
testNulls()492   public void testNulls() {
493     NullPointerTester tester =
494         new NullPointerTester()
495             .setDefault(SleepingStopwatch.class, stopwatch)
496             .setDefault(int.class, 1)
497             .setDefault(double.class, 1.0d);
498     tester.testStaticMethods(RateLimiter.class, Visibility.PACKAGE);
499     tester.testInstanceMethods(RateLimiter.create(5.0, stopwatch), Visibility.PACKAGE);
500   }
501 
testVerySmallDoubleValues()502   public void testVerySmallDoubleValues() throws Exception {
503     RateLimiter rateLimiter = RateLimiter.create(Double.MIN_VALUE, stopwatch);
504     assertTrue("Should acquire initial permit", rateLimiter.tryAcquire());
505     assertFalse("Should not acquire additional permit", rateLimiter.tryAcquire());
506     stopwatch.sleepMillis(5000);
507     assertFalse(
508         "Should not acquire additional permit even after sleeping", rateLimiter.tryAcquire());
509   }
510 
measureTotalTimeMillis(RateLimiter rateLimiter, int permits, Random random)511   private long measureTotalTimeMillis(RateLimiter rateLimiter, int permits, Random random) {
512     long startTime = stopwatch.instant;
513     while (permits > 0) {
514       int nextPermitsToAcquire = Math.max(1, random.nextInt(permits));
515       permits -= nextPermitsToAcquire;
516       rateLimiter.acquire(nextPermitsToAcquire);
517     }
518     rateLimiter.acquire(1); // to repay for any pending debt
519     return NANOSECONDS.toMillis(stopwatch.instant - startTime);
520   }
521 
assertEvents(String... events)522   private void assertEvents(String... events) {
523     assertEquals(Arrays.toString(events), stopwatch.readEventsAndClear());
524   }
525 
526   /**
527    * The stopwatch gathers events and presents them as strings. R0.6 means a delay of 0.6 seconds
528    * caused by the (R)ateLimiter U1.0 means the (U)ser caused the stopwatch to sleep for a second.
529    */
530   static class FakeStopwatch extends SleepingStopwatch {
531     long instant = 0L;
532     final List<String> events = Lists.newArrayList();
533 
534     @Override
readMicros()535     public long readMicros() {
536       return NANOSECONDS.toMicros(instant);
537     }
538 
sleepMillis(int millis)539     void sleepMillis(int millis) {
540       sleepMicros("U", MILLISECONDS.toMicros(millis));
541     }
542 
sleepMicros(String caption, long micros)543     void sleepMicros(String caption, long micros) {
544       instant += MICROSECONDS.toNanos(micros);
545       events.add(caption + String.format(Locale.ROOT, "%3.2f", (micros / 1000000.0)));
546     }
547 
548     @Override
sleepMicrosUninterruptibly(long micros)549     protected void sleepMicrosUninterruptibly(long micros) {
550       sleepMicros("R", micros);
551     }
552 
readEventsAndClear()553     String readEventsAndClear() {
554       try {
555         return events.toString();
556       } finally {
557         events.clear();
558       }
559     }
560 
561     @Override
toString()562     public String toString() {
563       return events.toString();
564     }
565   }
566 
567   /*
568    * Note: Mockito appears to lose its ability to Mock doGetRate as of Android 21. If we start
569    * testing with that version or newer, we'll need to suppress this test (or see if Mockito can be
570    * changed to support this).
571    */
testMockingMockito()572   public void testMockingMockito() throws Exception {
573     RateLimiter mock = Mockito.mock(RateLimiter.class);
574     doTestMocking(mock);
575   }
576 
577   @AndroidIncompatible // EasyMock Class Extension doesn't appear to work on Android.
testMockingEasyMock()578   public void testMockingEasyMock() throws Exception {
579     RateLimiter mock = EasyMock.createNiceMock(RateLimiter.class);
580     EasyMock.replay(mock);
581     doTestMocking(mock);
582   }
583 
doTestMocking(RateLimiter mock)584   private static void doTestMocking(RateLimiter mock) throws Exception {
585     for (Method method : RateLimiter.class.getMethods()) {
586       if (!isStatic(method.getModifiers())
587           && !NOT_WORKING_ON_MOCKS.contains(method.getName())
588           && !method.getDeclaringClass().equals(Object.class)) {
589         method.invoke(mock, arbitraryParameters(method));
590       }
591     }
592   }
593 
arbitraryParameters(Method method)594   private static Object[] arbitraryParameters(Method method) {
595     Class<?>[] parameterTypes = method.getParameterTypes();
596     Object[] params = new Object[parameterTypes.length];
597     for (int i = 0; i < parameterTypes.length; i++) {
598       params[i] = PARAMETER_VALUES.get(parameterTypes[i]);
599     }
600     return params;
601   }
602 
603   private static final ImmutableSet<String> NOT_WORKING_ON_MOCKS =
604       ImmutableSet.of("latestPermitAgeSec", "latestPermitAge", "setRate", "getAvailablePermits");
605 
606   // We would use ArbitraryInstances, but it returns 0, invalid for many RateLimiter methods.
607   private static final ImmutableClassToInstanceMap<Object> PARAMETER_VALUES =
608       ImmutableClassToInstanceMap.builder()
609           .put(int.class, 1)
610           .put(long.class, 1L)
611           .put(double.class, 1.0)
612           .put(TimeUnit.class, SECONDS)
613           .build();
614 }
615