/* * 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.core.spi.store.Store; import org.ehcache.core.spi.store.Store.RemoveStatus; import org.ehcache.core.spi.store.Store.ReplaceStatus; import org.ehcache.event.EventType; import org.ehcache.core.spi.store.events.StoreEvent; import org.ehcache.core.spi.store.events.StoreEventListener; import org.ehcache.expiry.Duration; import org.ehcache.expiry.Expirations; import org.ehcache.core.spi.function.BiFunction; import org.ehcache.core.spi.function.Function; import org.ehcache.internal.TestTimeSource; import org.ehcache.spi.test.After; import org.ehcache.spi.test.Before; import org.ehcache.spi.test.SPITest; import org.hamcrest.Matcher; import java.util.concurrent.TimeUnit; import static org.ehcache.internal.store.StoreCreationEventListenerTest.eventType; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; /** * Tests expiry events according to the contract of the * {@link Store Store} interface. */ public class StoreExpiryEventListenerTest<K, V> extends SPIStoreTester<K, V> { private TestTimeSource timeSource; public StoreExpiryEventListenerTest(StoreFactory<K, V> factory) { super(factory); } final K k = factory.createKey(1L); final V v = factory.createValue(1l); final V v2 = factory.createValue(2l); protected Store<K, V> kvStore; @Before public void setUp() { timeSource = new TestTimeSource(); kvStore = factory.newStoreWithExpiry(Expirations.timeToLiveExpiration(new Duration(1, TimeUnit.MILLISECONDS)), timeSource); } @After public void tearDown() { if(kvStore != null) { factory.close(kvStore); } } @SPITest public void testGetOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.get(k), is(nullValue())); verifyListenerInteractions(listener); } @SPITest public void testContainsKeyOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.containsKey(k), is(false)); verifyListenerInteractions(listener); } @SPITest public void testPutIfAbsentOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.putIfAbsent(k, v), is(nullValue())); verifyListenerInteractions(listener); } @SPITest public void testRemoveOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.remove(k), is(false)); verifyListenerInteractions(listener); } @SPITest public void testConditionalRemoveOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.remove(k, v), is(RemoveStatus.KEY_MISSING)); verifyListenerInteractions(listener); } @SPITest public void testReplaceTwoArgsOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.replace(k, v), is(nullValue())); verifyListenerInteractions(listener); } @SPITest public void testReplaceThreeArgsOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.replace(k, v, v2), is(ReplaceStatus.MISS_NOT_PRESENT)); verifyListenerInteractions(listener); } @SPITest public void testComputeOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.compute(k, new BiFunction<K, V, V>() { @Override public V apply(K mappedKey, V mappedValue) { return v2; } }).value(), is(v2)); verifyListenerInteractions(listener); } @SPITest public void testComputeIfAbsentOnExpiration() throws Exception { kvStore.put(k, v); StoreEventListener<K, V> listener = addListener(kvStore); timeSource.advanceTime(1); assertThat(kvStore.computeIfAbsent(k, new Function<K, V>() { @Override public V apply(K mappedKey) { return v2; } }).value(), is(v2)); verifyListenerInteractions(listener); } private void verifyListenerInteractions(StoreEventListener<K, V> listener) { Matcher<StoreEvent<K, V>> matcher = eventType(EventType.EXPIRED); 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; } }