/* * 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.internal.store; import org.ehcache.Cache; import org.ehcache.core.spi.store.Store; import org.ehcache.event.EventType; import org.ehcache.core.spi.store.StoreAccessException; import org.ehcache.core.spi.function.BiFunction; import org.ehcache.core.spi.function.Function; import org.ehcache.core.spi.store.events.StoreEvent; import org.ehcache.core.spi.store.events.StoreEventListener; import org.ehcache.spi.test.After; import org.ehcache.spi.test.Ignore; import org.ehcache.spi.test.SPITest; import org.hamcrest.Matcher; import static org.ehcache.internal.store.StoreCreationEventListenerTest.eventType; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; /** * Tests eviction events according to the contract of the * {@link Store Store} interface. */ public class StoreEvictionEventListenerTest<K, V> extends SPIStoreTester<K, V> { public StoreEvictionEventListenerTest(StoreFactory<K, V> factory) { super(factory); } final K k = factory.createKey(1L); final V v = factory.createValue(1l); final K k2 = factory.createKey(2L); final V v2 = factory.createValue(2l); final V v3 = factory.createValue(3l); protected Store<K, V> kvStore; @After public void tearDown() { if (kvStore != null) { factory.close(kvStore); kvStore = null; } } @SPITest public void testPutOnEviction() throws Exception { kvStore = factory.newStoreWithCapacity(1L); kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); kvStore.put(k2, v2); verifyListenerInteractions(listener); } @SPITest public void testPutIfAbsentOnEviction() throws Exception { kvStore = factory.newStoreWithCapacity(1L); kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); kvStore.putIfAbsent(k2, v2); verifyListenerInteractions(listener); } @SPITest @Ignore(reason = "See comment") public void testReplaceTwoArgsOnEviction() throws Exception { // The following makes no sense, what we may want to test here is that replace with a bigger value evicts // But that would also mean supporting the fact that this may not impact the store (think count based) kvStore = factory.newStoreWithCapacity(1L); StoreEventListener<K, V> listener = addListener(kvStore); kvStore.put(k, v); kvStore.put(k2, v2); verifyListenerInteractions(listener); kvStore.replace(getOnlyKey(kvStore.iterator()), v3); assertThat(kvStore.get(getOnlyKey(kvStore.iterator())).value(), is(v3)); } @SPITest public void testComputeOnEviction() throws Exception { kvStore = factory.newStoreWithCapacity(1L); kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); kvStore.compute(k2, new BiFunction<K, V, V>() { @Override public V apply(K mappedKey, V mappedValue) { return v2; } }); verifyListenerInteractions(listener); } @SPITest public void testComputeIfAbsentOnEviction() throws Exception { kvStore = factory.newStoreWithCapacity(1L); kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); kvStore.computeIfAbsent(k2, new Function<K, V>() { @Override public V apply(K mappedKey) { return v2; } }); verifyListenerInteractions(listener); } private K getOnlyKey(Store.Iterator<Cache.Entry<K, Store.ValueHolder<V>>> iter) throws StoreAccessException { if (iter.hasNext()) { Cache.Entry<K, Store.ValueHolder<V>> entry = iter.next(); return entry.getKey(); } return null; } private void verifyListenerInteractions(StoreEventListener<K, V> listener) { Matcher<StoreEvent<K, V>> matcher = eventType(EventType.EVICTED); verify(listener).onEvent(argThat(matcher)); } private StoreEventListener<K, V> addListener(Store<K, V> kvStore) { @SuppressWarnings("unchecked") StoreEventListener<K, V> listener = mock(StoreEventListener.class); kvStore.getStoreEventSource().addEventListener(listener); return listener; } }