/* * Copyright Terracotta, Inc. * * 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 org.ehcache.integration.statistics; import java.lang.reflect.Field; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.stream.StreamSupport; import javax.cache.Cache; import javax.cache.CacheManager; import javax.cache.Caching; import javax.cache.spi.CachingProvider; import org.ehcache.config.CacheConfiguration; import org.ehcache.config.builders.CacheConfigurationBuilder; import org.ehcache.config.builders.ResourcePoolsBuilder; import org.ehcache.core.EhcacheManager; import org.ehcache.core.config.DefaultConfiguration; import org.ehcache.core.spi.service.StatisticsService; import org.ehcache.impl.config.persistence.DefaultPersistenceConfiguration; import org.ehcache.jsr107.EhcacheCachingProvider; import org.ehcache.spi.service.Service; import org.ehcache.spi.service.ServiceProvider; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Check that calculations are accurate according to specification. Each cache method have a different impact on the statistics * so each method should be tested */ public class JCacheCalculationTest extends AbstractCacheCalculationTest { private CacheManager cacheManager; private Cache<Integer, String> cache; public JCacheCalculationTest(ResourcePoolsBuilder poolBuilder) { super(poolBuilder); } @Before public void before() throws Exception { CachingProvider cachingProvider = Caching.getCachingProvider(); EhcacheCachingProvider ehcacheProvider = (EhcacheCachingProvider) cachingProvider; DefaultConfiguration configuration = new DefaultConfiguration(ehcacheProvider.getDefaultClassLoader(), new DefaultPersistenceConfiguration(diskPath.newFolder())); CacheConfiguration<Integer, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class, resources).build(); configuration.addCacheConfiguration("cache", cacheConfiguration); cacheManager = ehcacheProvider.getCacheManager(ehcacheProvider.getDefaultURI(), configuration); EhcacheManager ehcacheManager = cacheManager.unwrap(EhcacheManager.class); Field field = EhcacheManager.class.getDeclaredField("serviceLocator"); field.setAccessible(true); @SuppressWarnings("unchecked") ServiceProvider<Service> serviceProvider = (ServiceProvider<Service>)field.get(ehcacheManager); StatisticsService statisticsService = serviceProvider.getService(StatisticsService.class); cache = cacheManager.getCache("cache", Integer.class, String.class); cacheStatistics = statisticsService.getCacheStatistics("cache"); } @After public void after() { if(cacheManager != null) { cacheManager.close(); } } @Test public void clear() { cache.put(1, "a"); cache.put(2, "b"); changesOf(0, 0, 2, 0, 0); cache.clear(); changesOf(0, 0, 0, 0, 0); } @Test public void containsKey() { expect(cache.containsKey(1)).isFalse(); changesOf(0, 0, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); expect(cache.containsKey(1)).isTrue(); changesOf(0, 0, 0, 0, 0); } @Test public void get() { expect(cache.get(1)).isNull(); changesOf(0, 1, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); expect(cache.get(1)).isEqualTo("a"); changesOf(1, 0, 0, 0, 0); } @Test public void getAll() { expect(cache.getAll(asSet(1))).isEmpty(); changesOf(0, 1, 0, 0, 0); cache.put(1, "a"); cache.put(2, "b"); changesOf(0, 0, 2, 0, 0); expect(cache.getAll(asSet(1, 2, 3))).containsKeys(1, 2); changesOf(2, 1, 0, 0, 0); } @Test public void getAndPut() { expect(cache.getAndPut(1, "a")).isNull(); changesOf(0, 1, 1, 0, 0); cache.getAndPut(1, "b"); changesOf(1, 0, 1, 0, 1); cache.getAndPut(1, "b"); // again with the same value changesOf(1, 0, 1, 0, 1); } @Test public void getAndRemove() { expect(cache.getAndRemove(1)).isNull(); changesOf(0, 1, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); expect(cache.getAndRemove(1)).isEqualTo("a"); changesOf(1, 0, 0, 1, 0); } @Test public void getAndReplace() { expect(cache.getAndReplace(1, "a")).isNull(); changesOf(0, 1, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); expect(cache.getAndReplace(1, "b")).isEqualTo("a"); changesOf(1, 0, 1, 0, 1); } @Test public void invoke() { expect(cache.invoke(1, new GetEntryProcessor())).isNull(); // miss changesOf(0, 1, 0, 0, 0); expect(cache.invoke(1, new GetKeyEntryProcessor())).isEqualTo(1); // miss changesOf(0, 1, 0, 0, 0); expect(cache.invoke(1, new ExistEntryProcessor())).isEqualTo(false); // miss changesOf(0, 1, 0, 0, 0); expect(cache.invoke(1, new SetEntryProcessor("a"))).isEqualTo("a"); // put changesOf(0, 1, 1, 0, 0); // FIXME Why is there a miss? expect(cache.invoke(1, new SetEntryProcessor("b"))).isEqualTo("b"); // update changesOf(1, 0, 1, 0, 1); expect(cache.invoke(1, new GetEntryProcessor())).isEqualTo("b"); // hit changesOf(1, 0, 0, 0, 0); expect(cache.invoke(1, new GetKeyEntryProcessor())).isEqualTo(1); // hit changesOf(1, 0, 0, 0, 0); expect(cache.invoke(1, new ExistEntryProcessor())).isEqualTo(true); // hit changesOf(1, 0, 0, 0, 0); expect(cache.invoke(1, new RemoveEntryProcessor())).isNull(); // hit changesOf(1, 0, 0, 1, 0); // FIXME Why is there a hit? expect(cache.invoke(1, new RemoveEntryProcessor())).isNull(); // miss changesOf(0, 1, 0, 1, 0); // FIXME Why is there a remove? } @Test public void invokeAll() { Set<Integer> keys = asSet(1, 2, 3); cache.invokeAll(keys, new GetEntryProcessor()); // miss changesOf(0, 3, 0, 0, 0); cache.invokeAll(keys, new GetKeyEntryProcessor()); // miss changesOf(0, 3, 0, 0, 0); cache.invokeAll(keys, new ExistEntryProcessor()); // miss changesOf(0, 3, 0, 0, 0); cache.invokeAll(keys, new SetEntryProcessor("a")); // put changesOf(0, 3, 3, 0, 0); // FIXME Why is there misses? cache.invokeAll(keys, new SetEntryProcessor("b")); // update changesOf(3, 0, 3, 0, 3); // FIXME Why is there hits? cache.invokeAll(keys, new GetEntryProcessor()); // hit changesOf(3, 0, 0, 0, 0); cache.invokeAll(keys, new GetKeyEntryProcessor()); // hit changesOf(3, 0, 0, 0, 0); cache.invokeAll(keys, new ExistEntryProcessor()); // hit changesOf(3, 0, 0, 0, 0); cache.invokeAll(asSet(2, 3, 4), new GetEntryProcessor()); // asymetric get changesOf(2, 1, 0, 0, 0); cache.invokeAll(keys, new RemoveEntryProcessor()); // hit changesOf(3, 0, 0, 3, 0); // FIXME Why is there a hit? cache.invokeAll(keys, new RemoveEntryProcessor()); // miss changesOf(0, 3, 0, 3, 0); // FIXME Why is there a remove? } @Test public void iterator() { cache.put(1, "a"); cache.put(2, "b"); changesOf(0, 0, 2, 0, 0); Iterator<Cache.Entry<Integer, String>> iterator = cache.iterator(); changesOf(0, 0, 0, 0, 0); iterator.next().getKey(); changesOf(1, 0, 0, 0, 0); expect(iterator.hasNext()).isTrue(); changesOf(0, 0, 0, 0, 0); iterator.next().getKey(); changesOf(1, 0, 0, 0, 0); expect(iterator.hasNext()).isFalse(); changesOf(0, 0, 0, 0, 0); iterator.remove(); changesOf(0, 0, 0, 1, 0); } @Test public void foreach() { cache.put(1, "a"); cache.put(2, "b"); cache.put(3, "c"); changesOf(0, 0, 3, 0, 0); cache.forEach(e -> {}); changesOf(3, 0, 0, 0, 0); } @Test public void spliterator() { cache.put(1, "a"); cache.put(2, "b"); cache.put(3, "c"); changesOf(0, 0, 3, 0, 0); StreamSupport.stream(cache.spliterator(), false).forEach(e -> {}); changesOf(3, 0, 0, 0, 0); } @Test public void loadAll() throws InterruptedException { // Skipping loadAll for now } @Test public void put() { cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); cache.put(1, "b"); changesOf(0, 0, 1, 0, 1); } @Test public void putAll() { Map<Integer, String> vals = new HashMap<Integer, String>(); vals.put(1, "a"); vals.put(2, "b"); cache.putAll(vals); changesOf(0, 0, 2, 0, 0); vals.put(3, "c"); cache.putAll(vals); changesOf(0, 0, 3, 0, 2); } @Test public void putIfAbsent() { expect(cache.putIfAbsent(1, "a")).isTrue(); changesOf(0, 1, 1, 0, 0); expect(cache.putIfAbsent(1, "b")).isFalse(); changesOf(1, 0, 0, 0, 0); } @Test public void remove() { cache.remove(1); changesOf(0, 0, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); cache.remove(1); changesOf(0, 0, 0, 1, 0); } @Test public void removeKV() { expect(cache.remove(1, "a")).isFalse(); changesOf(0, 1, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); expect(cache.remove(1, "xxx")).isFalse(); changesOf(1, 0, 0, 0, 0); expect(cache.remove(1, "a")).isTrue(); changesOf(1, 0, 0, 1, 0); } @Test public void removeAll() { cache.put(1, "a"); cache.put(2, "b"); changesOf(0, 0, 2, 0, 0); cache.removeAll(); changesOf(0, 0, 0, 2, 0); } @Test public void removeAllKeys() { cache.put(1, "a"); cache.put(2, "b"); changesOf(0, 0, 2, 0, 0); cache.removeAll(asSet(1, 2, 3)); changesOf(0, 0, 0, 2, 0); } @Test public void replaceKV() { expect(cache.replace(1, "a")).isFalse(); changesOf(0, 1, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); expect(cache.replace(1, "b")).isTrue(); changesOf(1, 0, 1, 0, 1); } @Test public void replaceKON() { expect(cache.replace(1, "a", "b")).isFalse(); changesOf(0, 1, 0, 0, 0); cache.put(1, "a"); changesOf(0, 0, 1, 0, 0); expect(cache.replace(1, "xxx", "b")).isFalse(); changesOf(1, 0, 0, 0, 0); expect(cache.replace(1, "a", "b")).isTrue(); changesOf(1, 0, 1, 0, 1); } @Test public void testClearingStats() { // We do it twice because the second time we already have compensating counters, so the result might fail innerClear(); innerClear(); } private void innerClear() { cache.get(1); // one miss cache.getAll(asSet(1, 2, 3)); // 3 misses cache.put(1, "a"); // one put cache.put(1, "b"); // one put and update cache.putAll(Collections.singletonMap(2, "b")); // 1 put cache.get(1); // one hit cache.remove(1); // one remove cache.removeAll(); // one remove changesOf(1, 4, 3, 2, 1); cacheStatistics.clear(); changesOf(-1, -4, -3, -2, -1); } }