@Test(dataProvider = "caches") @CacheSpec(population = Population.EMPTY, refreshAfterWrite = Expire.ONE_MINUTE, executor = CacheExecutor.THREADED, removalListener = Listener.CONSUMING) public void put(CacheContext context) { AtomicBoolean refresh = new AtomicBoolean(); Integer key = context.absentKey(); Integer original = 1; Integer updated = 2; Integer refreshed = 3; 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)); assertThat(cache.asMap().put(key, updated), is(original)); refresh.set(true); await().until(() -> context.consumedNotifications().size(), is(2)); List<Integer> removed = context.consumedNotifications().stream() .map(RemovalNotification::getValue).collect(toList()); assertThat(cache.getIfPresent(key), is(updated)); assertThat(removed, containsInAnyOrder(original, refreshed)); assertThat(cache, hasRemovalNotifications(context, 2, RemovalCause.REPLACED)); assertThat(context, both(hasLoadSuccessCount(1)).and(hasLoadFailureCount(0))); }
/** * Creates a matcher that matches when both of the specified matchers match the examined object. * <p/> * For example: * <pre>assertThat("fab", both(containsString("a")).and(containsString("b")))</pre> */ @Factory public static <LHS> CombinableBothMatcher<LHS> both(Matcher<? super LHS> matcher) { return new CombinableBothMatcher<LHS>(matcher); }
@Test public void shouldCancelRecurringJob() throws Exception { // Given long period = 2; life.start(); JobHandle jobHandle = scheduler.scheduleRecurring( Group.INDEX_POPULATION, countInvocationsJob, period, MILLISECONDS ); awaitFirstInvocation(); // When jobHandle.cancel( false ); try { jobHandle.waitTermination(); fail( "Task should be terminated" ); } catch ( CancellationException ignored ) { // task should be canceled } // Then int recorded = invocations.get(); sleep( period * 100 ); // we can have task that is already running during cancellation so lets count it as well assertThat( invocations.get(), both( greaterThanOrEqualTo( recorded ) ).and( lessThanOrEqualTo( recorded + 1 ) ) ); }
@Test(dataProvider = "caches") @CacheSpec(population = Population.EMPTY, executor = CacheExecutor.THREADED, removalListener = Listener.CONSUMING) public void refresh_conflict(CacheContext context) { AtomicBoolean refresh = new AtomicBoolean(); Integer key = context.absentKey(); Integer original = 1; Integer updated = 2; Integer refreshed = 3; LoadingCache<Integer, Integer> cache = context.build(k -> { await().untilTrue(refresh); return refreshed; }); cache.put(key, original); cache.refresh(key); assertThat(cache.asMap().put(key, updated), is(original)); refresh.set(true); await().until(() -> context.consumedNotifications().size(), is(2)); List<Integer> removed = context.consumedNotifications().stream() .map(RemovalNotification::getValue).collect(toList()); assertThat(cache.getIfPresent(key), is(updated)); assertThat(removed, containsInAnyOrder(original, refreshed)); assertThat(cache, hasRemovalNotifications(context, 2, RemovalCause.REPLACED)); assertThat(context, both(hasLoadSuccessCount(1)).and(hasLoadFailureCount(0))); }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void merge_sameValue(Map<Integer, Integer> map, CacheContext context) { for (Integer key : context.firstMiddleLastKeys()) { Integer value = context.original().get(key); assertThat(map.merge(key, -key, (k, v) -> k), is(value)); } int count = context.firstMiddleLastKeys().size(); assertThat(context, both(hasMissCount(0)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(count)).and(hasLoadFailureCount(0))); for (Integer key : context.firstMiddleLastKeys()) { Integer value = context.original().get(key); assertThat(map.get(key), is(value)); } assertThat(map.size(), is(context.original().size())); if (context.isGuava()) { assertThat(map, hasRemovalNotifications(context, count, RemovalCause.REPLACED)); } else { assertThat(context.consumedNotifications(), hasSize(0)); } }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void compute_sameValue(Map<Integer, Integer> map, CacheContext context) { for (Integer key : context.firstMiddleLastKeys()) { Integer value = context.original().get(key); assertThat(map.compute(key, (k, v) -> v), is(value)); } int count = context.firstMiddleLastKeys().size(); assertThat(context, both(hasMissCount(0)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(count)).and(hasLoadFailureCount(0))); for (Integer key : context.firstMiddleLastKeys()) { Integer value = context.original().get(key); assertThat(map.get(key), is(value)); } assertThat(map.size(), is(context.original().size())); if (context.isGuava() || context.isAsync()) { assertThat(map, hasRemovalNotifications(context, count, RemovalCause.REPLACED)); } else { assertThat(context.consumedNotifications(), hasSize(0)); } }
@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))); }
@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))); }
@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))); }
@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())); }
@Test public void picksUpTypeFromLeftHandSideOfExpression() { @SuppressWarnings("unused") Matcher<String> matcher = CombinableMatcher.both(equalTo("yellow")).and(notNullValue(String.class)); } }
/** * Creates a matcher that matches when both of the specified matchers match the examined object. * For example: * <pre>assertThat("fab", both(containsString("a")).and(containsString("b")))</pre> */ public static <LHS> CombinableBothMatcher<LHS> both(Matcher<? super LHS> matcher) { return new CombinableBothMatcher<>(matcher); }
/** * Build a matcher. * * @param method The method to match * @param uri The uri to match * @return A matcher */ public static Matcher<Route> hasUriAndMethod(final String method, final String uri) { return both(new RouteHasMethod(method)).and(new RouteHasUri(uri)); }
@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(loader = { Loader.NEGATIVE, Loader.BULK_NEGATIVE }, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getAll_duplicates(LoadingCache<Integer, Integer> cache, CacheContext context) { Set<Integer> absentKeys = ImmutableSet.copyOf(Iterables.limit(context.absentKeys(), Ints.saturatedCast(context.maximum().max() - context.initialSize()))); Iterable<Integer> keys = Iterables.concat(absentKeys, absentKeys, context.original().keySet(), context.original().keySet()); Map<Integer, Integer> result = cache.getAll(keys); assertThat(context, hasMissCount(absentKeys.size())); assertThat(context, hasHitCount(context.initialSize())); assertThat(result.keySet(), is(equalTo(ImmutableSet.copyOf(keys)))); int loads = context.loader().isBulk() ? 1 : absentKeys.size(); assertThat(context, both(hasLoadSuccessCount(loads)).and(hasLoadFailureCount(0))); }
@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())); }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(loader = Loader.IDENTITY, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void refresh_present_differentValue( LoadingCache<Integer, Integer> cache, CacheContext context) { for (Integer key : context.firstMiddleLastKeys()) { cache.refresh(key); // records a hit assertThat(cache.get(key), is(key)); } int count = context.firstMiddleLastKeys().size(); assertThat(cache.estimatedSize(), is(context.initialSize())); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.REPLACED)); assertThat(context, both(hasMissCount(0)).and(hasHitCount(count))); assertThat(context, both(hasLoadSuccessCount(count)).and(hasLoadFailureCount(0))); }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void refresh_present_sameValue( LoadingCache<Integer, Integer> cache, CacheContext context) { for (Integer key : context.firstMiddleLastKeys()) { cache.refresh(key); } int count = context.firstMiddleLastKeys().size(); assertThat(context, both(hasMissCount(0)).and(hasHitCount(0))); assertThat(context, both(hasLoadSuccessCount(count)).and(hasLoadFailureCount(0))); for (Integer key : context.firstMiddleLastKeys()) { assertThat(cache.get(key), is(context.original().get(key))); } assertThat(cache.estimatedSize(), is(context.initialSize())); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.REPLACED)); }
@CheckNoWriter @Test(dataProvider = "caches") @CacheSpec(loader = { Loader.NEGATIVE, Loader.BULK_NEGATIVE }, population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }, removalListener = { Listener.DEFAULT, Listener.REJECTING }) public void getAll_duplicates(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) { Set<Integer> absentKeys = ImmutableSet.copyOf(Iterables.limit(context.absentKeys(), Ints.saturatedCast(context.maximum().max() - context.initialSize()))); Iterable<Integer> keys = Iterables.concat(absentKeys, absentKeys, context.original().keySet(), context.original().keySet()); Map<Integer, Integer> result = cache.getAll(keys).join(); assertThat(context, hasMissCount(absentKeys.size())); assertThat(context, hasHitCount(context.initialSize())); assertThat(result.keySet(), is(equalTo(ImmutableSet.copyOf(keys)))); int loads = context.loader().isBulk() ? 1 : absentKeys.size(); assertThat(context, both(hasLoadSuccessCount(loads)).and(hasLoadFailureCount(0))); }