RateLimiter { public boolean tryAcquire() { long now = System.nanoTime() / 1_000_000; long toBeExpired = now - expireTime; synchronized (this) { long oldest = requests[position]; if (oldest < toBeExpired) { requests[position] = now; position = (position + 1) % requests.length; return true; } return false; } } RateLimiter(int maxLimit, long expireTime); boolean tryAcquire();  }
@Test public void allowExpire() throws InterruptedException { int size = 3; RateLimiter rateLimiter = new RateLimiter(size, 0); for (int i = 0; i < size; i++) { assertTrue("Filling up", rateLimiter.tryAcquire()); } for (int i = 0; i < size; i++) { Thread.sleep(1); assertTrue("Should be expired", rateLimiter.tryAcquire()); } }
@Test public void shoudBlock() { int size = 3; RateLimiter rateLimiter = new RateLimiter(size, TimeUnit.SECONDS.toMillis(30)); for (int i = 0; i < size; i++) { assertTrue("Filling up", rateLimiter.tryAcquire()); } assertFalse("Should be full and no entry should be expired", rateLimiter.tryAcquire()); }
@Test public void blockedNotAdded() throws InterruptedException { RateLimiter rateLimiter = new RateLimiter(1, 100); assertTrue("Filling up", rateLimiter.tryAcquire()); Thread.sleep(50); assertFalse("Expired too early", rateLimiter.tryAcquire()); Thread.sleep(50 + THRESHOLD_MILLI); assertTrue("Request not released", rateLimiter.tryAcquire()); }