DefaultRateLimitedCache implements RateLimitedCache<K> { public boolean acquire(K key, final Runnable cacheHit) { try (Scope ss = tracer.spanBuilder("DefaultRateLimitedCache").startScopedSpan()) { Span span = tracer.getCurrentSpan(); if (cache.get(key) != null) { cacheHit.run(); span.addAnnotation("Found key in cache"); return false; } span.addAnnotation("Acquiring rate limiter"); rateLimiter.acquire(); span.addAnnotation("Acquired rate limiter"); if (cache.putIfAbsent(key, true) != null) { cacheHit.run(); return false; } return true; } } @java.beans.ConstructorProperties({ "cache", "rateLimiter" })  DefaultRateLimitedCache(final ConcurrentMap<K, Boolean> cache,
                                   final RateLimiter rateLimiter); boolean acquire(K key, final Runnable cacheHit); int size();  }
@Test public void testCacheEarlyHit() throws ExecutionException, RateLimitExceededException { final DefaultRateLimitedCache<K> c = new DefaultRateLimitedCache<K>(cache, rateLimiter); doReturn(value).when(cache).get(key); assertEquals(false, c.acquire(key, notifier)); verify(cache).get(key); verify(rateLimiter, never()).tryAcquire(); verify(cache, never()).putIfAbsent(key, true); }
@Test public void testGet() throws ExecutionException, RateLimitExceededException { final DefaultRateLimitedCache<K> c = new DefaultRateLimitedCache<K>(cache, rateLimiter); doReturn(null).when(cache).get(key); doReturn(1D).when(rateLimiter).acquire(); doReturn(null).when(cache).putIfAbsent(key, true); assertEquals(true, c.acquire(key, notifier)); verify(cache).get(key); verify(rateLimiter).acquire(); verify(cache).putIfAbsent(key, true); }