/* * Copyright 2014 Ben Manes. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.benmanes.caffeine.cache; import static com.github.benmanes.caffeine.cache.IsCacheReserializable.reserializable; import static com.github.benmanes.caffeine.cache.testing.CacheWriterVerifier.verifyWriter; import static com.github.benmanes.caffeine.cache.testing.HasRemovalNotifications.hasRemovalNotifications; import static com.github.benmanes.caffeine.cache.testing.HasStats.hasHitCount; import static com.github.benmanes.caffeine.cache.testing.HasStats.hasLoadFailureCount; import static com.github.benmanes.caffeine.cache.testing.HasStats.hasLoadSuccessCount; import static com.github.benmanes.caffeine.cache.testing.HasStats.hasMissCount; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import com.github.benmanes.caffeine.cache.stats.CacheStats; import com.github.benmanes.caffeine.cache.testing.CacheContext; import com.github.benmanes.caffeine.cache.testing.CacheProvider; import com.github.benmanes.caffeine.cache.testing.CacheSpec; import com.github.benmanes.caffeine.cache.testing.CacheSpec.Compute; import com.github.benmanes.caffeine.cache.testing.CacheSpec.Implementation; import com.github.benmanes.caffeine.cache.testing.CacheSpec.Listener; import com.github.benmanes.caffeine.cache.testing.CacheSpec.Population; import com.github.benmanes.caffeine.cache.testing.CacheSpec.ReferenceType; import com.github.benmanes.caffeine.cache.testing.CacheSpec.Writer; import com.github.benmanes.caffeine.cache.testing.CacheValidationListener; import com.github.benmanes.caffeine.cache.testing.CheckNoStats; import com.github.benmanes.caffeine.cache.testing.CheckNoWriter; import com.github.benmanes.caffeine.cache.testing.RejectingCacheWriter.DeleteException; import com.github.benmanes.caffeine.cache.testing.RejectingCacheWriter.WriteException; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; /** * The test cases for the {@link Cache} interface that simulate the most generic usages. These * tests do not validate eviction management, concurrency behavior, or the {@link Cache#asMap()} * view. * * @author ben.manes@gmail.com (Ben Manes) */ @Listeners(CacheValidationListener.class) @Test(dataProviderClass = CacheProvider.class) public final class CacheTest { /* ---------------- size -------------- */ @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void estimatedSize(Cache<Integer, Integer> cache, CacheContext context) { assertThat(cache.estimatedSize(), is(context.initialSize())); } /* ---------------- getIfPresent -------------- */ @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void getIfPresent_nullKey(Cache<Integer, Integer> cache, CacheContext context) { cache.getIfPresent(null); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getIfPresent_absent(Cache<Integer, Integer> cache, CacheContext context) { assertThat(cache.getIfPresent(context.absentKey()), is(nullValue())); assertThat(context, both(hasMissCount(1)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(0))); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void getIfPresent_present(Cache<Integer, Integer> cache, CacheContext context) { assertThat(cache.getIfPresent(context.firstKey()), is(not(nullValue()))); assertThat(cache.getIfPresent(context.middleKey()), is(not(nullValue()))); assertThat(cache.getIfPresent(context.lastKey()), is(not(nullValue()))); assertThat(context, both(hasMissCount(0)).and(hasHitCount(3))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(0))); } /* ---------------- get -------------- */ @CacheSpec @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void get_nullKey(Cache<Integer, Integer> cache, CacheContext context) { cache.get(null, Function.identity()); } @CacheSpec @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void get_nullLoader(Cache<Integer, Integer> cache, CacheContext context) { cache.get(context.absentKey(), null); } @CacheSpec @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void get_nullKeyAndLoader(Cache<Integer, Integer> cache, CacheContext context) { cache.get(null, null); } @CacheSpec @CheckNoWriter @Test(dataProvider = "caches", expectedExceptions = IllegalStateException.class) public void get_throwsException(Cache<Integer, Integer> cache, CacheContext context) { try { cache.get(context.absentKey(), key -> { throw new IllegalStateException(); }); } finally { assertThat(context, both(hasMissCount(1)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(1))); } } @CacheSpec @CheckNoWriter @Test(dataProvider = "caches") public void get_absent_null(LoadingCache<Integer, Integer> cache, CacheContext context) { assertThat(cache.get(context.absentKey(), k -> null), is(nullValue())); assertThat(context, both(hasMissCount(1)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(1))); } @CacheSpec @CheckNoWriter @Test(dataProvider = "caches") public void get_absent(Cache<Integer, Integer> cache, CacheContext context) { Integer key = context.absentKey(); Integer value = cache.get(key, k -> context.absentValue()); assertThat(value, is(context.absentValue())); assertThat(context, both(hasMissCount(1)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(1)).and(hasLoadFailureCount(0))); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void get_present(Cache<Integer, Integer> cache, CacheContext context) { Function<Integer, Integer> loader = key -> { throw new RuntimeException(); }; assertThat(cache.get(context.firstKey(), loader), is(context.original().get(context.firstKey()))); assertThat(cache.get(context.middleKey(), loader), is(context.original().get(context.middleKey()))); assertThat(cache.get(context.lastKey(), loader), is(context.original().get(context.lastKey()))); assertThat(context, both(hasMissCount(0)).and(hasHitCount(3))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(0))); } /* ---------------- getAllPresent -------------- */ @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void getAllPresent_iterable_null(Cache<Integer, Integer> cache, CacheContext context) { cache.getAllPresent(null); } @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void getAllPresent_iterable_nullKey(Cache<Integer, Integer> cache, CacheContext context) { cache.getAllPresent(Collections.singletonList(null)); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getAllPresent_iterable_empty(Cache<Integer, Integer> cache, CacheContext context) { Map<Integer, Integer> result = cache.getAllPresent(ImmutableList.of()); assertThat(result.size(), is(0)); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getAllPresent_absent(Cache<Integer, Integer> cache, CacheContext context) { Map<Integer, Integer> result = cache.getAllPresent(context.absentKeys()); assertThat(result.size(), is(0)); int count = context.absentKeys().size(); assertThat(context, both(hasMissCount(count)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(0))); } @CacheSpec @CheckNoWriter @Test(dataProvider = "caches", expectedExceptions = UnsupportedOperationException.class) public void getAllPresent_immutable(Cache<Integer, Integer> cache, CacheContext context) { cache.getAllPresent(context.absentKeys()).clear(); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.PARTIAL, Population.FULL }, removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getAllPresent_present_partial(Cache<Integer, Integer> cache, CacheContext context) { Map<Integer, Integer> expect = new HashMap<>(); expect.put(context.firstKey(), context.original().get(context.firstKey())); expect.put(context.middleKey(), context.original().get(context.middleKey())); expect.put(context.lastKey(), context.original().get(context.lastKey())); Map<Integer, Integer> result = cache.getAllPresent(expect.keySet()); assertThat(result, is(equalTo(expect))); assertThat(context, both(hasMissCount(0)).and(hasHitCount(expect.size()))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(0))); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getAllPresent_present_full(Cache<Integer, Integer> cache, CacheContext context) { Map<Integer, Integer> result = cache.getAllPresent(context.original().keySet()); assertThat(result, is(equalTo(context.original()))); assertThat(context, both(hasMissCount(0)).and(hasHitCount(result.size()))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(0))); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getAllPresent_duplicates(Cache<Integer, Integer> cache, CacheContext context) { Iterable<Integer> keys = Iterables.concat( context.absentKeys(), context.absentKeys(), context.original().keySet(), context.original().keySet()); Map<Integer, Integer> result = cache.getAllPresent(keys); int misses = context.absentKeys().size(); int hits = context.original().keySet().size(); if (context.isGuava()) { // does not filter duplicate queries misses += misses; hits += hits; } assertThat(result, is(equalTo(context.original()))); assertThat(context, both(hasMissCount(misses)).and(hasHitCount(hits))); assertThat(context, both(hasLoadSuccessCount(0)).and(hasLoadFailureCount(0))); } /* ---------------- put -------------- */ @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void put_insert(Cache<Integer, Integer> cache, CacheContext context) { cache.put(context.absentKey(), context.absentValue()); assertThat(cache.estimatedSize(), is(context.initialSize() + 1)); assertThat(cache.getIfPresent(context.absentKey()), is(context.absentValue())); } @CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void put_replace_sameValue(Cache<Integer, Integer> cache, CacheContext context) { for (Integer key : context.firstMiddleLastKeys()) { Integer value = context.original().get(key); cache.put(key, value); assertThat(cache.getIfPresent(key), is(value)); } assertThat(cache.estimatedSize(), is(context.initialSize())); int count = context.firstMiddleLastKeys().size(); if (context.isGuava() || context.isAsync()) { assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.REPLACED)); } } @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void put_replace_differentValue(Cache<Integer, Integer> cache, CacheContext context) { for (Integer key : context.firstMiddleLastKeys()) { cache.put(key, context.absentValue()); assertThat(cache.getIfPresent(key), is(context.absentValue())); verifyWriter(context, (verifier, writer) -> { verifier.wrote(key, context.absentValue()); }); } assertThat(cache.estimatedSize(), is(context.initialSize())); int count = context.firstMiddleLastKeys().size(); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.REPLACED)); } @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void put_nullKey(Cache<Integer, Integer> cache, CacheContext context) { cache.put(null, context.absentValue()); } @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void put_nullValue(Cache<Integer, Integer> cache, CacheContext context) { cache.put(context.absentKey(), null); } @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void put_nullKeyAndValue(Cache<Integer, Integer> cache, CacheContext context) { cache.put(null, null); } @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = WriteException.class) @CacheSpec(implementation = Implementation.Caffeine, keys = ReferenceType.STRONG, compute = Compute.SYNC, writer = Writer.EXCEPTIONAL, removalListener = Listener.REJECTING) public void put_insert_writerFails(Cache<Integer, Integer> cache, CacheContext context) { try { cache.put(context.absentKey(), context.absentValue()); } finally { assertThat(cache.asMap(), equalTo(context.original())); } } @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = WriteException.class) @CacheSpec(implementation = Implementation.Caffeine, keys = ReferenceType.STRONG, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, compute = Compute.SYNC, writer = Writer.EXCEPTIONAL, removalListener = Listener.REJECTING) public void put_replace_writerFails(Cache<Integer, Integer> cache, CacheContext context) { try { cache.put(context.middleKey(), context.absentValue()); } finally { assertThat(cache.asMap(), equalTo(context.original())); } } /* ---------------- put all -------------- */ @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void putAll_insert(Cache<Integer, Integer> cache, CacheContext context) { int startKey = context.original().size() + 1; Map<Integer, Integer> entries = IntStream .range(startKey, 100 + startKey).boxed() .collect(Collectors.toMap(Function.identity(), key -> -key)); cache.putAll(entries); assertThat(cache.estimatedSize(), is(100 + context.initialSize())); verifyWriter(context, (verifier, writer) -> { verifier.wroteAll(entries); }); } @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, removalListener = { Listener.DEFAULT, Listener.CONSUMING }) public void putAll_replace(Cache<Integer, Integer> cache, CacheContext context) { Map<Integer, Integer> entries = new HashMap<>(context.original()); entries.replaceAll((key, value) -> value + 1); cache.putAll(entries); assertThat(cache.asMap(), is(equalTo(entries))); assertThat(cache, hasRemovalNotifications(context, entries.size(), RemovalCause.REPLACED)); verifyWriter(context, (verifier, writer) -> { verifier.wroteAll(entries); }); } @Test(dataProvider = "caches") @CacheSpec(population = { Population.PARTIAL, Population.FULL }, removalListener = { Listener.DEFAULT, Listener.CONSUMING }) public void putAll_mixed(Cache<Integer, Integer> cache, CacheContext context) { Map<Integer, Integer> entries = new HashMap<>(); Map<Integer, Integer> replaced = new HashMap<>(); context.original().forEach((key, value) -> { if ((key % 2) == 0) { value++; replaced.put(key, value); } entries.put(key, value); }); cache.putAll(entries); assertThat(cache.asMap(), is(equalTo(entries))); Map<Integer, Integer> expect = (context.isGuava() || context.isAsync()) ? entries : replaced; assertThat(cache, hasRemovalNotifications(context, expect.size(), RemovalCause.REPLACED)); verifyWriter(context, (verifier, writer) -> { verifier.wroteAll(replaced); }); } @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void putAll_empty(Cache<Integer, Integer> cache, CacheContext context) { cache.putAll(new HashMap<>()); assertThat(cache.estimatedSize(), is(context.initialSize())); } @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void putAll_null(Cache<Integer, Integer> cache, CacheContext context) { cache.putAll(null); } @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = WriteException.class) @CacheSpec(implementation = Implementation.Caffeine, keys = ReferenceType.STRONG, compute = Compute.SYNC, writer = Writer.EXCEPTIONAL, removalListener = Listener.REJECTING) public void putAll_insert_writerFails(Cache<Integer, Integer> cache, CacheContext context) { try { cache.putAll(context.absent()); } finally { assertThat(cache.asMap(), equalTo(context.original())); } } @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = WriteException.class) @CacheSpec(implementation = Implementation.Caffeine, keys = ReferenceType.STRONG, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, compute = Compute.SYNC, writer = Writer.EXCEPTIONAL, removalListener = Listener.REJECTING) public void putAll_replace_writerFails(Cache<Integer, Integer> cache, CacheContext context) { try { cache.putAll(ImmutableMap.of(context.middleKey(), context.absentValue())); } finally { assertThat(cache.asMap(), equalTo(context.original())); } } /* ---------------- invalidate -------------- */ @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void invalidate_absent(Cache<Integer, Integer> cache, CacheContext context) { cache.invalidate(context.absentKey()); assertThat(cache.estimatedSize(), is(context.initialSize())); } @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void invalidate_present(Cache<Integer, Integer> cache, CacheContext context) { for (Integer key : context.firstMiddleLastKeys()) { cache.invalidate(key); verifyWriter(context, (verifier, writer) -> { verifier.deleted(key, context.original().get(key), RemovalCause.EXPLICIT); }); } int count = context.firstMiddleLastKeys().size(); assertThat(cache.estimatedSize(), is(context.initialSize() - count)); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.EXPLICIT)); } @CheckNoWriter @CheckNoStats @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void invalidate_nullKey(Cache<Integer, Integer> cache, CacheContext context) { cache.invalidate(null); } @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = DeleteException.class) @CacheSpec(implementation = Implementation.Caffeine, keys = ReferenceType.STRONG, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, compute = Compute.SYNC, writer = Writer.EXCEPTIONAL, removalListener = Listener.REJECTING) public void invalidate_writerFails(Cache<Integer, Integer> cache, CacheContext context) { try { cache.invalidate(context.middleKey()); } finally { assertThat(cache.asMap(), equalTo(context.original())); } } /* ---------------- invalidateAll -------------- */ @CacheSpec @Test(dataProvider = "caches") public void invalidateAll(Cache<Integer, Integer> cache, CacheContext context) { cache.invalidateAll(); assertThat(cache.estimatedSize(), is(0L)); assertThat(cache, hasRemovalNotifications(context, context.original().size(), RemovalCause.EXPLICIT)); verifyWriter(context, (verifier, writer) -> { verifier.deletedAll(context.original(), RemovalCause.EXPLICIT); }); } @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches") @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void invalidateAll_empty(Cache<Integer, Integer> cache, CacheContext context) { cache.invalidateAll(new HashSet<>()); } @Test(dataProvider = "caches") @CacheSpec(population = { Population.PARTIAL, Population.FULL }) public void invalidateAll_partial(Cache<Integer, Integer> cache, CacheContext context) { List<Integer> keys = cache.asMap().keySet().stream() .filter(i -> ((i % 2) == 0)) .collect(Collectors.toList()); cache.invalidateAll(keys); assertThat(cache.estimatedSize(), is(context.initialSize() - keys.size())); assertThat(cache, hasRemovalNotifications(context, keys.size(), RemovalCause.EXPLICIT)); verifyWriter(context, (verifier, writer) -> { verifier.deletedAll(Maps.filterKeys(context.original(), Predicates.in(keys)), RemovalCause.EXPLICIT); }); } @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void invalidateAll_full(Cache<Integer, Integer> cache, CacheContext context) { cache.invalidateAll(context.original().keySet()); assertThat(cache.estimatedSize(), is(0L)); assertThat(cache, hasRemovalNotifications(context, context.original().size(), RemovalCause.EXPLICIT)); verifyWriter(context, (verifier, writer) -> { verifier.deletedAll(context.original(), RemovalCause.EXPLICIT); }); } @CacheSpec @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = NullPointerException.class) public void invalidateAll_null(Cache<Integer, Integer> cache, CacheContext context) { cache.invalidateAll(null); } @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = DeleteException.class) @CacheSpec(implementation = Implementation.Caffeine, keys = ReferenceType.STRONG, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, compute = Compute.SYNC, writer = Writer.EXCEPTIONAL, removalListener = Listener.REJECTING) public void invalidateAll_partial_writerFails(Cache<Integer, Integer> cache, CacheContext context) { try { cache.invalidateAll(context.firstMiddleLastKeys()); } finally { assertThat(cache.asMap(), equalTo(context.original())); } } @CheckNoStats @Test(dataProvider = "caches", expectedExceptions = DeleteException.class) @CacheSpec(implementation = Implementation.Caffeine, keys = ReferenceType.STRONG, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, compute = Compute.SYNC, writer = Writer.EXCEPTIONAL, removalListener = Listener.REJECTING) public void invalidateAll_full_writerFails(Cache<Integer, Integer> cache, CacheContext context) { try { cache.invalidateAll(); } finally { assertThat(cache.asMap(), equalTo(context.original())); } } /* ---------------- cleanup -------------- */ @CacheSpec @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches") public void cleanup(Cache<Integer, Integer> cache, CacheContext context) { cache.cleanUp(); } /* ---------------- stats -------------- */ @CacheSpec @CheckNoWriter @CheckNoStats @Test(dataProvider = "caches") public void stats(Cache<Integer, Integer> cache, CacheContext context) { CacheStats stats = cache.stats() .plus(new CacheStats(1, 2, 3, 4, 5, 6, 7) .minus(new CacheStats(6, 5, 4, 3, 2, 1, 0))); assertThat(stats, is(new CacheStats(0, 0, 0, 1, 3, 5, 7))); assertThat(cache.policy().isRecordingStats(), is(context.isRecordingStats())); } /* ---------------- serialize -------------- */ @CheckNoStats @Test(dataProvider = "caches") @CacheSpec(writer = Writer.EXCEPTIONAL) public void serialize(Cache<Integer, Integer> cache, CacheContext context) { assertThat(cache, is(reserializable())); } }