/* * 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.core; import org.ehcache.Status; import org.ehcache.config.CacheConfiguration; import org.ehcache.core.config.BaseCacheConfiguration; import org.ehcache.core.config.ResourcePoolsHelper; import org.ehcache.core.statistics.CacheOperationOutcomes; import org.ehcache.core.spi.store.StoreAccessException; import org.ehcache.spi.loaderwriter.CacheWritingException; import org.ehcache.expiry.Duration; import org.ehcache.expiry.Expirations; import org.ehcache.expiry.Expiry; import org.ehcache.spi.loaderwriter.CacheLoaderWriter; import org.hamcrest.CoreMatchers; import org.junit.Test; import org.mockito.Mock; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.EnumSet; import static org.ehcache.core.util.Matchers.holding; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; /** * Provides testing of basic REPLACE(key, newValue, oldValue) operations on an {@code EhcacheWithLoaderWriter}. * * @author Clifford W. Johnson */ public class EhcacheWithLoaderWriterBasicReplaceValueTest extends EhcacheBasicCrudBase { @Mock protected CacheLoaderWriter<String, String> cacheLoaderWriter; @Test public void testReplaceValueNullNullNull() { final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace(null, null, null); fail(); } catch (NullPointerException e) { // expected } } @Test public void testReplaceKeyNullNull() { final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", null, null); fail(); } catch (NullPointerException e) { // expected } } @Test public void testReplaceKeyValueNull() { final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", "oldValue", null); fail(); } catch (NullPointerException e) { // expected } } @Test public void testReplaceKeyNullValue() { final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", null, "newValue"); fail(); } catch (NullPointerException e) { // expected } } @Test public void testReplaceNullValueNull() { final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace(null, "oldValue", null); fail(); } catch (NullPointerException e) { // expected } } @Test public void testReplaceNullValueValue() { final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace(null, "oldValue", "newValue"); fail(); } catch (NullPointerException e) { // expected } } @Test public void testReplaceNullNullValue() { final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace(null, null, "newValue"); fail(); } catch (NullPointerException e) { // expected } } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * </ul> */ @Test public void testReplaceValueNoStoreEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().containsKey("key"), is(false)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_NOT_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value in {@code Store}</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("unequalValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value in {@code Store}</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); assertTrue(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("newValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.HIT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryStoreAccessException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryStoreAccessException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryStoreAccessException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>key not present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryNoCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.<String, String>emptyMap()); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().containsKey("key"), is(false)); assertThat(fakeWriter.getEntryMap().containsKey("key"), is(false)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_NOT_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>key not present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryNoCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.<String, String>emptyMap()); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("unequalValue"))); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>key not present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryNoCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.<String, String>emptyMap()); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertTrue(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("newValue"))); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.HIT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key not present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryStoreAccessExceptionNoCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.<String, String>emptyMap()); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); assertThat(fakeWriter.getEntryMap().containsKey("key"), is(false)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key not present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryStoreAccessExceptionNoCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.<String, String>emptyMap()); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key not present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryStoreAccessExceptionNoCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.<String, String>emptyMap()); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>key with unequal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryUnequalCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "unequalValue")); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is("unequalValue")); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("unequalValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>key with unequal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryUnequalCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "unequalValue")); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("unequalValue"))); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("unequalValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>key with unequal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryUnequalCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "unequalValue")); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertTrue(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("newValue"))); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.HIT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key with unequal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryStoreAccessExceptionUnequalCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "unequalValue")); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("unequalValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key with unequal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryStoreAccessExceptionUnequalCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "unequalValue")); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("unequalValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key with unequal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryStoreAccessExceptionUnequalCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "unequalValue")); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(false)); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>key with equal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryEqualCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertThat(ehcache.replace("key", "oldValue", "newValue"), is(true)); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is("newValue")); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("newValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.HIT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>key with equal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryEqualCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("unequalValue"))); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>key with equal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryEqualCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter); assertTrue(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), is(equalTo("newValue"))); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("newValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.HIT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key with equal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryStoreAccessExceptionEqualCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(true)); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("newValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key with equal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryStoreAccessExceptionEqualCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(true)); // Broken initial state: CacheLoaderWriter check omitted validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>key with equal value present via {@code CacheLoaderWriter}</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryStoreAccessExceptionEqualCacheLoaderWriterEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); ehcache.replace("key", "oldValue", "newValue"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), eq(true)); assertThat(fakeWriter.getEntryMap().get("key"), is(equalTo("newValue"))); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>{@code CacheLoaderWriter.write} throws</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryCacheLoaderWriterException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); doThrow(new Exception()).when(this.cacheLoaderWriter).write("key", "newValue"); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", "oldValue", "newValue"); fail(); } catch (CacheWritingException e) { // expected } verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); validateStats(ehcache, EnumSet.noneOf(CacheOperationOutcomes.ReplaceOutcome.class)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>{@code CacheLoaderWriter.write} throws</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryCacheLoaderWriterException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); doThrow(new Exception()).when(this.cacheLoaderWriter).write("key", "newValue"); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); assertFalse(ehcache.replace("key", "oldValue", "newValue")); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.MISS_PRESENT)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>{@code CacheLoaderWriter.write} throws</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryCacheLoaderWriterException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); doThrow(new Exception()).when(this.cacheLoaderWriter).write("key", "newValue"); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", "oldValue", "newValue"); fail(); } catch (CacheWritingException e) { // Expected } verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); validateStats(ehcache, EnumSet.noneOf(CacheOperationOutcomes.ReplaceOutcome.class)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key not present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>{@code CacheLoaderWriter.write} throws</li> * </ul> */ @Test public void testReplaceValueNoStoreEntryStoreAccessExceptionCacheLoaderWriterException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>emptyMap()); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); doThrow(new Exception()).when(this.cacheLoaderWriter).write("key", "newValue"); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", "oldValue", "newValue"); fail(); } catch (CacheWritingException e) { // expected } verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), any(CacheWritingException.class)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with unequal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>{@code CacheLoaderWriter.write} throws</li> * </ul> */ @Test public void testReplaceValueUnequalStoreEntryStoreAccessExceptionCacheLoaderWriterException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "unequalValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); doThrow(new Exception()).when(this.cacheLoaderWriter).write("key", "newValue"); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", "oldValue", "newValue"); fail(); } catch (CacheWritingException e) { // expected } verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), any(CacheWritingException.class)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } /** * Tests the effect of a {@link EhcacheWithLoaderWriter#replace(Object, Object, Object)} for * <ul> * <li>key with equal value present in {@code Store}</li> * <li>>{@code Store.compute} throws</li> * <li>{@code CacheLoaderWriter.write} throws</li> * </ul> */ @Test public void testReplaceValueEqualStoreEntryStoreAccessExceptionCacheLoaderWriterException() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.singletonMap("key", "oldValue")); this.store = spy(fakeStore); doThrow(new StoreAccessException("")).when(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.singletonMap("key", "oldValue")); this.cacheLoaderWriter = spy(fakeWriter); doThrow(new Exception()).when(this.cacheLoaderWriter).write("key", "newValue"); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(this.cacheLoaderWriter); try { ehcache.replace("key", "oldValue", "newValue"); fail(); } catch (CacheWritingException e) { // Expected } verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verify(this.spiedResilienceStrategy) .replaceFailure(eq("key"), eq("oldValue"), eq("newValue"), any(StoreAccessException.class), any(CacheWritingException.class)); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.FAILURE)); } @Test public void testReplaceWithImmediatelyExpiredEntry() throws Exception { final FakeStore fakeStore = new FakeStore(Collections.<String, String>singletonMap("key", "old-value")); this.store = spy(fakeStore); final FakeCacheLoaderWriter fakeWriter = new FakeCacheLoaderWriter(Collections.<String, String>singletonMap("key", "old-value")); @SuppressWarnings("unchecked") final Expiry<String, String> expiry = mock(Expiry.class); when(expiry.getExpiryForUpdate(eq("key"), argThat(holding("old-value")), eq("value"))).thenReturn(Duration.ZERO); final EhcacheWithLoaderWriter<String, String> ehcache = this.getEhcache(fakeWriter, expiry); ehcache.replace("key", "old-value", "value"); verify(this.store).compute(eq("key"), getAnyBiFunction(), getBooleanNullaryFunction()); verifyZeroInteractions(this.spiedResilienceStrategy); assertThat(fakeStore.getEntryMap().get("key"), nullValue()); assertThat(fakeWriter.getEntryMap().get("key"), equalTo("value")); validateStats(ehcache, EnumSet.of(CacheOperationOutcomes.ReplaceOutcome.HIT)); } /** * Gets an initialized {@link EhcacheWithLoaderWriter Ehcache} instance using the * {@link org.ehcache.spi.loaderwriter.CacheLoaderWriter CacheLoaderWriter} provided. * * @param cacheLoaderWriter * the {@code CacheLoaderWriter} to use; may be {@code null} * * @return a new {@code EhcacheWithLoaderWriter} instance */ private EhcacheWithLoaderWriter<String, String> getEhcache(final CacheLoaderWriter<String, String> cacheLoaderWriter) { return getEhcache(cacheLoaderWriter, Expirations.noExpiration()); } private EhcacheWithLoaderWriter<String, String> getEhcache(final CacheLoaderWriter<String, String> cacheLoaderWriter, Expiry<? super String, ? super String> expiry) { CacheConfiguration<String, String> config = new BaseCacheConfiguration<String, String>(String.class, String.class, null, null, expiry, ResourcePoolsHelper.createHeapOnlyPools()); final EhcacheWithLoaderWriter<String, String> ehcache = new EhcacheWithLoaderWriter<String, String>(config, this.store, cacheLoaderWriter, cacheEventDispatcher, LoggerFactory.getLogger(EhcacheWithLoaderWriter.class + "-" + "EhcacheWithLoaderWriterBasicReplaceValueTest")); ehcache.init(); assertThat("cache not initialized", ehcache.getStatus(), CoreMatchers.is(Status.AVAILABLE)); this.spiedResilienceStrategy = this.setResilienceStrategySpy(ehcache); return ehcache; } }