/* * Copyright (c) 2008-2017, Hazelcast, Inc. 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.hazelcast.client.cache.impl.nearcache; import com.hazelcast.cache.ICache; import com.hazelcast.client.cache.impl.HazelcastClientCacheManager; import com.hazelcast.client.cache.impl.HazelcastClientCachingProvider; import com.hazelcast.client.config.ClientConfig; import com.hazelcast.client.impl.HazelcastClientProxy; import com.hazelcast.client.test.TestHazelcastFactory; import com.hazelcast.config.CacheConfig; import com.hazelcast.config.Config; import com.hazelcast.config.InMemoryFormat; import com.hazelcast.config.NearCacheConfig; import com.hazelcast.config.NearCacheConfig.LocalUpdatePolicy; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.LifecycleEvent; import com.hazelcast.instance.LifecycleServiceImpl; import com.hazelcast.internal.nearcache.NearCache; import com.hazelcast.internal.nearcache.NearCacheManager; import com.hazelcast.monitor.NearCacheStats; import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.properties.GroupProperty; import com.hazelcast.test.AssertTask; import com.hazelcast.test.HazelcastTestSupport; import org.junit.After; import org.junit.Before; import javax.cache.configuration.FactoryBuilder; import javax.cache.integration.CacheLoader; import javax.cache.integration.CacheLoaderException; import javax.cache.integration.CompletionListener; import javax.cache.spi.CachingProvider; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import static com.hazelcast.spi.properties.GroupProperty.CACHE_INVALIDATION_MESSAGE_BATCH_FREQUENCY_SECONDS; import static java.lang.String.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; public abstract class ClientNearCacheTestSupport extends HazelcastTestSupport { protected static final String DEFAULT_CACHE_NAME = "ClientCache"; protected static final int DEFAULT_RECORD_COUNT = 100; protected static final int MAX_TTL_SECONDS = 2; protected static final int MAX_IDLE_SECONDS = 1; protected final TestHazelcastFactory hazelcastFactory = new TestHazelcastFactory(); protected HazelcastInstance serverInstance; @Before public final void factoryInitialization() { serverInstance = hazelcastFactory.newHazelcastInstance(createConfig()); } @After public final void factoryShutdown() { hazelcastFactory.shutdownAll(); } protected Config createConfig() { return new Config(); } protected ClientConfig createClientConfig() { return new ClientConfig(); } protected CacheConfig createCacheConfig(InMemoryFormat inMemoryFormat) { CacheConfig cacheConfig = new CacheConfig().setName(DEFAULT_CACHE_NAME).setInMemoryFormat(inMemoryFormat); //noinspection unchecked cacheConfig.setCacheLoaderFactory(FactoryBuilder.factoryOf(ClientNearCacheTestSupport.TestCacheLoader.class)); return cacheConfig; } protected NearCacheConfig createNearCacheConfig(InMemoryFormat inMemoryFormat) { return new NearCacheConfig() .setName(DEFAULT_CACHE_NAME) .setInMemoryFormat(inMemoryFormat); } protected String generateValueFromKey(Integer key) { return "Value-" + key; } protected NearCacheTestContext createNearCacheTest(String cacheName, NearCacheConfig nearCacheConfig, CacheConfig cacheConfig) { ClientConfig clientConfig = createClientConfig(); clientConfig.addNearCacheConfig(nearCacheConfig); HazelcastClientProxy client = (HazelcastClientProxy) hazelcastFactory.newHazelcastClient(clientConfig); NearCacheManager nearCacheManager = client.client.getNearCacheManager(); CachingProvider provider = HazelcastClientCachingProvider.createCachingProvider(client); HazelcastClientCacheManager cacheManager = (HazelcastClientCacheManager) provider.getCacheManager(); //noinspection unchecked ICache<Object, String> cache = cacheManager.createCache(cacheName, cacheConfig); NearCache<Data, String> nearCache = nearCacheManager.getNearCache(cacheManager.getCacheNameWithPrefix(cacheName)); return new NearCacheTestContext(client, cacheManager, nearCacheManager, cache, nearCache); } protected NearCacheTestContext createNearCacheTest(String cacheName, NearCacheConfig nearCacheConfig) { CacheConfig cacheConfig = createCacheConfig(nearCacheConfig.getInMemoryFormat()); return createNearCacheTest(cacheName, nearCacheConfig, cacheConfig); } protected NearCacheTestContext createNearCacheTestAndFillWithData(String cacheName, NearCacheConfig nearCacheConfig) { return createNearCacheTestAndFillWithData(cacheName, nearCacheConfig, false); } protected NearCacheTestContext createNearCacheTestAndFillWithData(String cacheName, NearCacheConfig nearCacheConfig, boolean putIfAbsent) { NearCacheTestContext nearCacheTestContext = createNearCacheTest(cacheName, nearCacheConfig); for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { if (putIfAbsent) { nearCacheTestContext.cache.putIfAbsent(i, generateValueFromKey(i)); } else { nearCacheTestContext.cache.put(i, generateValueFromKey(i)); } } return nearCacheTestContext; } protected void putAndGetFromCacheAndThenGetFromClientNearCache(InMemoryFormat inMemoryFormat) { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); NearCacheTestContext nearCacheTestContext = createNearCacheTestAndFillWithData(DEFAULT_CACHE_NAME, nearCacheConfig); for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { assertNull(nearCacheTestContext.nearCache.get(nearCacheTestContext.serializationService.toData(i))); } for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { // get records so they will be stored in Near Cache nearCacheTestContext.cache.get(i); } for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { String expectedValue = generateValueFromKey(i); Data keyData = nearCacheTestContext.serializationService.toData(i); assertEquals(expectedValue, nearCacheTestContext.nearCache.get(keyData)); } } protected void putToCacheAndThenGetFromClientNearCacheInternal(InMemoryFormat inMemoryFormat, boolean putIfAbsent) { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setLocalUpdatePolicy(LocalUpdatePolicy.CACHE_ON_UPDATE); NearCacheTestContext nearCacheTestContext = createNearCacheTestAndFillWithData(DEFAULT_CACHE_NAME, nearCacheConfig, putIfAbsent); for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { String expectedValue = generateValueFromKey(i); Data keyData = nearCacheTestContext.serializationService.toData(i); assertEquals(expectedValue, nearCacheTestContext.nearCache.get(keyData)); } } protected void putToCacheAndThenGetFromClientNearCache(InMemoryFormat inMemoryFormat) { putToCacheAndThenGetFromClientNearCacheInternal(inMemoryFormat, false); } protected void putIfAbsentToCacheAndThenGetFromClientNearCache(InMemoryFormat inMemoryFormat) { putToCacheAndThenGetFromClientNearCacheInternal(inMemoryFormat, true); } protected void putAsyncToCacheAndThenGetFromClientNearCacheImmediately(InMemoryFormat inMemoryFormat) throws Exception { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setLocalUpdatePolicy(LocalUpdatePolicy.CACHE_ON_UPDATE); NearCacheTestContext nearCacheTestContext = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); for (int i = 0; i < 10 * DEFAULT_RECORD_COUNT; i++) { String expectedValue = generateValueFromKey(i); Data keyData = nearCacheTestContext.serializationService.toData(i); Future future = nearCacheTestContext.cache.putAsync(i, expectedValue); future.get(); assertEquals(expectedValue, nearCacheTestContext.nearCache.get(keyData)); } } protected void putToCacheAndUpdateFromOtherNodeThenGetUpdatedFromClientNearCache(InMemoryFormat inMemoryFormat) { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setInvalidateOnChange(true); NearCacheTestContext nearCacheTestContext1 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); final NearCacheTestContext nearCacheTestContext2 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); // put cache record from client-1 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { nearCacheTestContext1.cache.put(i, generateValueFromKey(i)); } // get records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final Integer key = i; final String value = nearCacheTestContext2.cache.get(key); // records are stored in the cache as async not sync, so these records will be there in cache eventually assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertEquals(value, nearCacheTestContext2.nearCache.get(keyData)); } }); } // update cache record from client-1 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { nearCacheTestContext1.cache.put(i, generateValueFromKey(DEFAULT_RECORD_COUNT + i)); } // get updated records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final int key = i; // records are stored in the Near Cache will be invalidated eventually, since cache records are updated assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertNull(nearCacheTestContext2.nearCache.get(keyData)); } }); } // get updated records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final Integer key = i; final String value = nearCacheTestContext2.cache.get(key); // records are stored in the cache as async not sync, so these records will be there in cache eventually assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertEquals(value, nearCacheTestContext2.nearCache.get(keyData)); } }); } } protected void putToCacheAndGetInvalidationEventWhenNodeShutdown(InMemoryFormat inMemoryFormat) { Config config = createConfig(); config.setProperty(GroupProperty.CACHE_INVALIDATION_MESSAGE_BATCH_SIZE.getName(), String.valueOf(Integer.MAX_VALUE)); config.setProperty(CACHE_INVALIDATION_MESSAGE_BATCH_FREQUENCY_SECONDS.getName(), String.valueOf(Integer.MAX_VALUE)); HazelcastInstance instanceToShutdown = hazelcastFactory.newHazelcastInstance(config); warmUpPartitions(serverInstance, instanceToShutdown); waitAllForSafeState(serverInstance, instanceToShutdown); NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setInvalidateOnChange(true); nearCacheConfig.setLocalUpdatePolicy(LocalUpdatePolicy.CACHE_ON_UPDATE); final NearCacheTestContext nearCacheTestContext1 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); final NearCacheTestContext nearCacheTestContext2 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); Map<String, String> keyAndValues = new HashMap<String, String>(); // put cache record from client-1 to instance which is going to be shutdown for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { String key = generateKeyOwnedBy(instanceToShutdown); String value = generateValueFromKey(i); nearCacheTestContext1.cache.put(key, value); keyAndValues.put(key, value); } // verify that records are exist at Near Cache of client-1 because `local-update-policy` is `CACHE` for (Map.Entry<String, String> entry : keyAndValues.entrySet()) { String key = entry.getKey(); String exceptedValue = entry.getValue(); String actualValue = nearCacheTestContext1.nearCache.get(nearCacheTestContext1.serializationService.toData(key)); assertEquals(exceptedValue, actualValue); } // remove records through client-2 so there will be invalidation events // to send to client to invalidate its Near Cache for (Map.Entry<String, String> entry : keyAndValues.entrySet()) { nearCacheTestContext2.cache.remove(entry.getKey()); } // we don't shutdown the instance because in case of shutdown even though events are published to event queue, // they may not be processed in the event queue due to shutdown event queue executor or may not be sent // to client endpoint due to IO handler shutdown // for not to making test fragile, we just simulate shutting down by sending its event through `LifeCycleService`, // so the node should flush invalidation events before shutdown ((LifecycleServiceImpl) instanceToShutdown.getLifecycleService()) .fireLifecycleEvent(LifecycleEvent.LifecycleState.SHUTTING_DOWN); // verify that records in the Near Cache of client-1 are invalidated eventually when instance shutdown for (Map.Entry<String, String> entry : keyAndValues.entrySet()) { final String key = entry.getKey(); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext1.serializationService.toData(key); assertNull(nearCacheTestContext1.nearCache.get(keyData)); } }); } } protected void putToCacheAndRemoveFromOtherNodeThenCantGetUpdatedFromClientNearCache(InMemoryFormat inMemoryFormat) { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setInvalidateOnChange(true); NearCacheTestContext nearCacheTestContext1 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); final NearCacheTestContext nearCacheTestContext2 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); // put cache record from client-1 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { nearCacheTestContext1.cache.put(i, generateValueFromKey(i)); } // get records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final Integer key = i; final String value = nearCacheTestContext2.cache.get(key); // records are stored in the cache as async not sync, so these records will be there in cache eventually assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertEquals(value, nearCacheTestContext2.nearCache.get(keyData)); } }); } // delete cache record from client-1 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { nearCacheTestContext1.cache.remove(i); } // can't get deleted records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final int key = i; // records are stored in the Near Cache will be invalidated eventually, since cache records are updated. assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertNull(nearCacheTestContext2.nearCache.get(keyData)); } }); } } protected void testLoadAllNearCacheInvalidation(InMemoryFormat inMemoryFormat) throws Exception { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setInvalidateOnChange(true); NearCacheTestContext nearCacheTestContext1 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); final NearCacheTestContext nearCacheTestContext2 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); Set<Integer> testKeys = new HashSet<Integer>(DEFAULT_RECORD_COUNT); Set<Integer> loadKeys = new HashSet<Integer>(DEFAULT_RECORD_COUNT / 2); for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { if (i % 2 == 0) { loadKeys.add(i); } testKeys.add(i); } // populate cache from client-1 for (int i : testKeys) { nearCacheTestContext1.cache.put(i, generateValueFromKey(i)); } final CountDownLatch completed = new CountDownLatch(1); nearCacheTestContext1.cache.loadAll(loadKeys, true, new CompletionListener() { @Override public void onCompletion() { completed.countDown(); } @Override public void onException(Exception e) { } }); assertTrue("completed.await() didn't finish in 3 seconds", completed.await(3, TimeUnit.SECONDS)); // can't get replaced keys from client-2 for (int i : loadKeys) { final int key = i; // records are stored in the Near Cache will be invalidated eventually, since cache records are updated assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertNull(nearCacheTestContext2.nearCache.get(keyData)); } }); } } protected void putToCacheAndClearOrDestroyThenCantGetAnyRecordFromClientNearCache(InMemoryFormat inMemoryFormat) { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setInvalidateOnChange(true); NearCacheTestContext nearCacheTestContext1 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); final NearCacheTestContext nearCacheTestContext2 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); // put cache record from client-1 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { nearCacheTestContext1.cache.put(i, generateValueFromKey(i)); } // get records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final Integer key = i; final String value = nearCacheTestContext2.cache.get(key); // records are stored in the cache as async not sync, so these records will be there in cache eventually assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertEquals(value, nearCacheTestContext2.nearCache.get(keyData)); } }); } nearCacheTestContext1.cache.clear(); // can't get expired records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final int key = i; // records are stored in the Near Cache will be invalidated eventually, since cache records are cleared assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertNull(nearCacheTestContext2.nearCache.get(keyData)); } }); } } protected void doTestGetAllReturnsFromNearCache(InMemoryFormat inMemoryFormat) { if (inMemoryFormat != InMemoryFormat.OBJECT) { return; } NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); NearCacheTestContext nearCacheTestContext = createNearCacheTestAndFillWithData(DEFAULT_CACHE_NAME, nearCacheConfig); for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { assertNull(nearCacheTestContext.nearCache.get(nearCacheTestContext.serializationService.toData(i))); } for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { // get records so they will be stored in Near Cache nearCacheTestContext.cache.get(i); } for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { Data keyData = nearCacheTestContext.serializationService.toData(i); // check if same reference to verify data coming from Near Cache assertSame(nearCacheTestContext.cache.get(i), nearCacheTestContext.nearCache.get(keyData)); } } protected void putToCacheAndDontInvalidateFromClientNearCacheWhenPerEntryInvalidationIsDisabled(InMemoryFormat inMemoryFormat) { CacheConfig cacheConfig = createCacheConfig(inMemoryFormat); cacheConfig.setDisablePerEntryInvalidationEvents(true); NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setInvalidateOnChange(true); NearCacheTestContext nearCacheTestContext1 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig, cacheConfig); final NearCacheTestContext nearCacheTestContext2 = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig, cacheConfig); // put cache record from client-1 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { nearCacheTestContext1.cache.put(i, generateValueFromKey(i)); } // get records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final Integer key = i; final String value = nearCacheTestContext2.cache.get(key); // records are stored in the cache as async not sync, so these records will be there in cache eventually assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertEquals(value, nearCacheTestContext2.nearCache.get(keyData)); } }); } // update cache record from client-1 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { // update the cache records with new values nearCacheTestContext1.cache.put(i, generateValueFromKey(i + DEFAULT_RECORD_COUNT)); } int invalidationEventFlushFreq = Integer.parseInt(CACHE_INVALIDATION_MESSAGE_BATCH_FREQUENCY_SECONDS.getDefaultValue()); // wait some time and if there are invalidation events to be sent in batch // (we assume that they should be flushed, received and processed in this time window already) sleepSeconds(2 * invalidationEventFlushFreq); // get records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { String actualValue = nearCacheTestContext2.cache.get(i); String expectedValue = generateValueFromKey(i); // verify that still we have old records in the Near Cache, because, per entry invalidation events are disabled assertEquals(expectedValue, actualValue); } nearCacheTestContext1.cache.clear(); // can't get expired records from client-2 for (int i = 0; i < DEFAULT_RECORD_COUNT; i++) { final int key = i; // records are stored in the Near Cache will be invalidated eventually, since cache records are cleared // because we just disable per entry invalidation events, not full-flush events assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { Data keyData = nearCacheTestContext2.serializationService.toData(key); assertNull(nearCacheTestContext2.nearCache.get(keyData)); } }); } } protected void testNearCacheExpiration_withTTL(InMemoryFormat inMemoryFormat) { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setTimeToLiveSeconds(MAX_TTL_SECONDS); testNearCacheExpiration(nearCacheConfig, MAX_TTL_SECONDS); } protected void testNearCacheExpiration_withMaxIdle(InMemoryFormat inMemoryFormat) { NearCacheConfig nearCacheConfig = createNearCacheConfig(inMemoryFormat); nearCacheConfig.setTimeToLiveSeconds(MAX_IDLE_SECONDS); testNearCacheExpiration(nearCacheConfig, MAX_IDLE_SECONDS); } private void testNearCacheExpiration(NearCacheConfig nearCacheConfig, int expireSeconds) { final int size = 147; final NearCacheTestContext context = createNearCacheTest(DEFAULT_CACHE_NAME, nearCacheConfig); for (int i = 0; i < size; i++) { context.cache.put(i, "value-" + i); context.cache.get(i); } final NearCacheStats statsBeforeExpiration = getNearCacheStats(context.cache); assertTrue(format("we expected to have all cache entries in the Near Cache or already expired (%s)", statsBeforeExpiration), statsBeforeExpiration.getOwnedEntryCount() + statsBeforeExpiration.getExpirations() >= 0); sleepSeconds(expireSeconds + 1); assertTrueEventually(new AssertTask() { public void run() { // map.get() triggers Near Cache eviction/expiration process, // but we need to call this on every assert since the Near Cache has a cooldown for TTL cleanups context.cache.get(0); NearCacheStats stats = getNearCacheStats(context.cache); assertEquals("we expect the same hits", statsBeforeExpiration.getHits(), stats.getHits()); assertEquals("we expect the same misses", statsBeforeExpiration.getMisses(), stats.getMisses()); assertEquals("we expect all entries beside the 'trigger entry' to be deleted from the Near Cache", 1, stats.getOwnedEntryCount()); assertEquals("we did not expect any entries to be evicted from the Near Cache", 0, stats.getEvictions()); assertTrue(format("we expect at least %d entries to be expired from the Near Cache", size), stats.getExpirations() >= size); } }); } protected NearCacheStats getNearCacheStats(ICache cache) { return cache.getLocalCacheStatistics().getNearCacheStatistics(); } public static class TestCacheLoader implements CacheLoader<Integer, String> { @Override public String load(Integer key) throws CacheLoaderException { return String.valueOf(2 * key); } @Override public Map<Integer, String> loadAll(Iterable<? extends Integer> keys) throws CacheLoaderException { Map<Integer, String> entries = new HashMap<Integer, String>(); for (int key : keys) { entries.put(key, String.valueOf(2 * key)); } return entries; } } }