@Override public void delete(Integer key, Integer value, RemovalCause cause) { evicting.set(true); await().untilTrue(done); } };
@Override public Integer reload(Integer key, Integer oldValue) { int count = reloading.incrementAndGet(); await().untilTrue(reloaded); return count; } });
private void block() { await().atMost(20, TimeUnit.SECONDS).untilTrue(unblock); unblock.set(false); } }
void checkDrainBlocks(BoundedLocalCache<Integer, Integer> localCache, Runnable task) { AtomicBoolean done = new AtomicBoolean(); ReentrantLock lock = localCache.evictionLock; lock.lock(); try { executor.execute(() -> { localCache.lazySetDrainStatus(REQUIRED); task.run(); done.set(true); }); await().until(lock::hasQueuedThreads); } finally { lock.unlock(); } await().untilTrue(done); } }
@Test public void childExecutorService() { executorServiceRule.submit(() -> { executorService = Executors.newCachedThreadPool(); executorService.submit(() -> terminateLatch.await(TIMEOUT_MILLIS, MILLISECONDS)); executorService.submit(() -> terminateLatch.await(TIMEOUT_MILLIS, MILLISECONDS)); submittedChildren.set(true); }); await().untilTrue(submittedChildren); assertThat(executorServiceRule.getThreads().size()).isLessThanOrEqualTo(1); }
@Test(dataProvider = "caches") @CacheSpec(compute = Compute.SYNC, implementation = Implementation.Caffeine, population = Population.EMPTY, maximumSize = Maximum.FULL) public void drain_nonblocking(Cache<Integer, Integer> cache, CacheContext context) { BoundedLocalCache<Integer, Integer> localCache = asBoundedLocalCache(cache); AtomicBoolean done = new AtomicBoolean(); Runnable task = () -> { localCache.lazySetDrainStatus(REQUIRED); localCache.scheduleDrainBuffers(); done.set(true); }; localCache.evictionLock.lock(); try { ConcurrentTestHarness.execute(task); await().untilTrue(done); } finally { localCache.evictionLock.unlock(); } }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, maximumSize = Maximum.FULL, weigher = CacheWeigher.COLLECTION, population = Population.EMPTY, keys = ReferenceType.STRONG, values = ReferenceType.STRONG) @SuppressWarnings("FutureReturnValueIgnored") public void put_asyncWeight(AsyncLoadingCache<Integer, List<Integer>> cache, CacheContext context, Eviction<?, ?> eviction) { AtomicBoolean ready = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CompletableFuture<List<Integer>> valueFuture = CompletableFuture.supplyAsync(() -> { Awaits.await().untilTrue(ready); return ImmutableList.of(1, 2, 3, 4, 5); }); valueFuture.whenComplete((r, e) -> done.set(true)); cache.put(context.absentKey(), valueFuture); assertThat(eviction.weightedSize().getAsLong(), is(0L)); assertThat(cache.synchronous().estimatedSize(), is(1L)); ready.set(true); Awaits.await().untilTrue(done); Awaits.await().until(() -> eviction.weightedSize().getAsLong(), is(5L)); Awaits.await().until(() -> cache.synchronous().estimatedSize(), is(1L)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, maximumSize = Maximum.ZERO, weigher = CacheWeigher.COLLECTION, population = Population.EMPTY, keys = ReferenceType.STRONG, values = ReferenceType.STRONG) @SuppressWarnings("FutureReturnValueIgnored") public void evict_zero_async(AsyncLoadingCache<Integer, List<Integer>> cache, CacheContext context, Eviction<?, ?> eviction) { AtomicBoolean ready = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CompletableFuture<List<Integer>> valueFuture = CompletableFuture.supplyAsync(() -> { Awaits.await().untilTrue(ready); return ImmutableList.of(1, 2, 3, 4, 5); }); valueFuture.whenComplete((r, e) -> done.set(true)); cache.put(context.absentKey(), valueFuture); assertThat(eviction.weightedSize().getAsLong(), is(0L)); assertThat(cache.synchronous().estimatedSize(), is(1L)); ready.set(true); Awaits.await().untilTrue(done); Awaits.await().until(() -> eviction.weightedSize().getAsLong(), is(0L)); Awaits.await().until(() -> cache.synchronous().estimatedSize(), is(0L)); assertThat(context, hasRemovalNotifications(context, 1, RemovalCause.SIZE)); verifyWriter(context, (verifier, writer) -> verifier.deletions(1, RemovalCause.SIZE)); }
@Test public void rescheduleDrainBuffers() { AtomicBoolean evicting = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CacheWriter<Integer, Integer> writer = new CacheWriter<Integer, Integer>() { @Override public void write(Integer key, Integer value) {} @Override public void delete(Integer key, Integer value, RemovalCause cause) { evicting.set(true); await().untilTrue(done); } }; BoundedLocalCache<Integer, Integer> map = asBoundedLocalCache( Caffeine.newBuilder().writer(writer).maximumSize(0L).build()); map.put(1, 1); await().untilTrue(evicting); map.put(2, 2); assertThat(map.drainStatus, is(PROCESSING_TO_REQUIRED)); done.set(true); await().until(() -> map.drainStatus, is(IDLE)); }
@Test(dataProvider = "caches") @CacheSpec(expiryTime = Expire.FOREVER, expiry = { CacheExpiry.CREATE, CacheExpiry.WRITE, CacheExpiry.ACCESS }) public void expiry_bounds(Cache<Integer, Integer> cache, CacheContext context) { context.ticker().advance(System.nanoTime()); AtomicBoolean running = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); Integer key = context.absentKey(); cache.put(key, key); try { ConcurrentTestHarness.execute(() -> { while (!done.get()) { context.ticker().advance(1, TimeUnit.MINUTES); cache.get(key, Integer::new); running.set(true); } }); await().untilTrue(running); cache.cleanUp(); assertThat(cache.get(key, Integer::new), sameInstance(key)); } finally { done.set(true); } }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(loader = Loader.NULL, executor = CacheExecutor.THREADED) public void getFunc_absent_cancelled(AsyncCache<Integer, Integer> cache, CacheContext context) { AtomicBoolean done = new AtomicBoolean(); CompletableFuture<Integer> valueFuture = cache.get(context.absentKey(), k -> { Awaits.await().until(done::get); return null; }); valueFuture.whenComplete((r, e) -> done.set(true)); valueFuture.cancel(true); Awaits.await().untilTrue(done); await().until(() -> context, both(hasMissCount(1)).and(hasHitCount(0))); await().until(() -> context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(1))); assertThat(valueFuture.isDone(), is(true)); assertThat(cache.getIfPresent(context.absentKey()), is(nullValue())); }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(executor = CacheExecutor.THREADED, executorFailure = ExecutorFailure.IGNORED) public void getFunc_absent_failure_async(AsyncCache<Integer, Integer> cache, CacheContext context) { AtomicBoolean ready = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CompletableFuture<Integer> valueFuture = cache.get(context.absentKey(), k -> { Awaits.await().untilTrue(ready); throw new IllegalStateException(); }); valueFuture.whenComplete((r, e) -> done.set(true)); ready.set(true); Awaits.await().untilTrue(done); Awaits.await().until(() -> !cache.synchronous().asMap().containsKey(context.absentKey())); Awaits.await().until(() -> context, both(hasMissCount(1)).and(hasHitCount(0))); Awaits.await().until(() -> context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(1))); assertThat(valueFuture.isCompletedExceptionally(), is(true)); assertThat(cache.getIfPresent(context.absentKey()), is(nullValue())); }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(loader = Loader.NULL, executor = CacheExecutor.THREADED, executorFailure = ExecutorFailure.IGNORED) public void getFunc_absent_null_async(AsyncCache<Integer, Integer> cache, CacheContext context) { Integer key = context.absentKey(); AtomicBoolean ready = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CompletableFuture<Integer> valueFuture = cache.get(key, k -> { Awaits.await().untilTrue(ready); return null; }); valueFuture.whenComplete((r, e) -> done.set(true)); ready.set(true); Awaits.await().untilTrue(done); Awaits.await().until(() -> !cache.synchronous().asMap().containsKey(context.absentKey())); Awaits.await().until(() -> context, both(hasMissCount(1)).and(hasHitCount(0))); Awaits.await().until(() -> context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(1))); assertThat(valueFuture.isDone(), is(true)); assertThat(cache.synchronous().asMap(), not(hasKey(key))); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.EMPTY, refreshAfterWrite = Expire.ONE_MINUTE, executor = CacheExecutor.THREADED, compute = Compute.ASYNC, values = ReferenceType.STRONG) public void get_sameFuture(CacheContext context) { AtomicBoolean done = new AtomicBoolean(); AsyncLoadingCache<Integer, Integer> cache = context.buildAsync(key -> { await().untilTrue(done); return -key; }); Integer key = 1; cache.synchronous().put(key, key); CompletableFuture<Integer> original = cache.get(key); for (int i = 0; i < 10; i++) { context.ticker().advance(1, TimeUnit.MINUTES); CompletableFuture<Integer> next = cache.get(key); assertThat(next, is(sameInstance(original))); } done.set(true); await().until(() -> cache.synchronous().getIfPresent(key), is(-key)); }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(loader = Loader.EXCEPTIONAL, executor = CacheExecutor.THREADED, executorFailure = ExecutorFailure.IGNORED) public void get_absent_failure_async(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) throws InterruptedException { AtomicBoolean done = new AtomicBoolean(); Integer key = context.absentKey(); CompletableFuture<Integer> valueFuture = cache.get(key); valueFuture.whenComplete((r, e) -> done.set(true)); Awaits.await().untilTrue(done); Awaits.await().until(() -> !cache.synchronous().asMap().containsKey(context.absentKey())); Awaits.await().until(() -> context, both(hasMissCount(1)).and(hasHitCount(0))); Awaits.await().until(() -> context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(1))); assertThat(valueFuture.isCompletedExceptionally(), is(true)); assertThat(cache.getIfPresent(key), is(nullValue())); }
@Test(timeout = 2000L) public void atomicBooleanWithUntilTrue() throws Exception { new WasAddedModifier().start(); await().atMost(FIVE_SECONDS).untilTrue(wasAdded); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.EMPTY, executor = CacheExecutor.THREADED, compute = Compute.ASYNC, values = ReferenceType.STRONG) public void refresh(CacheContext context) { AtomicBoolean done = new AtomicBoolean(); AsyncLoadingCache<Integer, Integer> cache = context.buildAsync(key -> { await().untilTrue(done); return -key; }); Integer key = 1; cache.synchronous().put(key, key); CompletableFuture<Integer> original = cache.get(key); for (int i = 0; i < 10; i++) { context.ticker().advance(1, TimeUnit.SECONDS); cache.synchronous().refresh(key); CompletableFuture<Integer> next = cache.get(key); assertThat(next, is(sameInstance(original))); } done.set(true); await().until(() -> cache.synchronous().getIfPresent(key), is(-key)); }
@Test(timeout = 2000L) public void atomicBooleanWithUntilTrueWhenBooleanUsesDefaultValue() throws Exception { new WasAddedWithDefaultValue().start(); await().atMost(FIVE_SECONDS).untilTrue(wasAddedWithDefaultValue); }
@Test(dataProvider = "caches") @CacheSpec(population = Population.EMPTY, refreshAfterWrite = Expire.ONE_MINUTE, executor = CacheExecutor.THREADED, removalListener = Listener.CONSUMING) public void invalidate(CacheContext context) { AtomicBoolean refresh = new AtomicBoolean(); Integer key = context.absentKey(); Integer original = 1; Integer refreshed = 2; LoadingCache<Integer, Integer> cache = context.build(k -> { await().untilTrue(refresh); return refreshed; }); cache.put(key, original); context.ticker().advance(2, TimeUnit.MINUTES); assertThat(cache.getIfPresent(key), is(original)); cache.invalidate(key); refresh.set(true); await().until(() -> cache.getIfPresent(key), is(refreshed)); await().until(() -> cache, hasRemovalNotifications(context, 1, RemovalCause.EXPLICIT)); await().until(() -> context, both(hasLoadSuccessCount(1)).and(hasLoadFailureCount(0))); }
@Test(dataProvider = "caches") @CacheSpec(population = Population.EMPTY, executor = CacheExecutor.THREADED, removalListener = Listener.CONSUMING) public void refresh_invalidate(CacheContext context) { AtomicBoolean refresh = new AtomicBoolean(); Integer key = context.absentKey(); Integer original = 1; Integer refreshed = 2; LoadingCache<Integer, Integer> cache = context.build(k -> { await().untilTrue(refresh); return refreshed; }); cache.put(key, original); cache.refresh(key); cache.invalidate(key); refresh.set(true); await().until(() -> cache.getIfPresent(key), is(refreshed)); await().until(() -> cache, hasRemovalNotifications(context, 1, RemovalCause.EXPLICIT)); await().until(() -> context, both(hasLoadSuccessCount(1)).and(hasLoadFailureCount(0))); }