/*
* 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.Cache;
import org.ehcache.CacheManager;
import org.ehcache.CachePersistenceException;
import org.ehcache.PersistentCacheManager;
import org.ehcache.StateTransitionException;
import org.ehcache.Status;
import org.ehcache.UserManagedCache;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.Configuration;
import org.ehcache.config.ResourcePools;
import org.ehcache.config.ResourceType;
import org.ehcache.core.config.BaseCacheConfiguration;
import org.ehcache.core.config.DefaultConfiguration;
import org.ehcache.core.config.ResourcePoolsHelper;
import org.ehcache.core.events.CacheEventDispatcher;
import org.ehcache.core.events.CacheEventDispatcherFactory;
import org.ehcache.core.events.CacheEventListenerProvider;
import org.ehcache.core.events.CacheManagerListener;
import org.ehcache.core.internal.util.ClassLoading;
import org.ehcache.core.spi.service.LocalPersistenceService;
import org.ehcache.core.spi.store.Store;
import org.ehcache.spi.loaderwriter.CacheLoaderWriter;
import org.ehcache.spi.loaderwriter.CacheLoaderWriterProvider;
import org.ehcache.spi.loaderwriter.WriteBehindProvider;
import org.ehcache.spi.service.MaintainableService;
import org.ehcache.spi.service.Service;
import org.ehcache.spi.service.ServiceConfiguration;
import org.ehcache.spi.service.ServiceCreationConfiguration;
import org.ehcache.spi.service.ServiceProvider;
import org.hamcrest.CoreMatchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Matchers;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
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.anyCollection;
import static org.mockito.Matchers.anySet;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class EhcacheManagerTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
private static Map<String, CacheConfiguration<?, ?>> newCacheMap() {
return new HashMap<String, CacheConfiguration<?, ?>>();
}
private List<Service> minimunCacheManagerServices() {
return new ArrayList<Service>(Arrays.asList(
mock(Store.Provider.class),
mock(CacheLoaderWriterProvider.class),
mock(WriteBehindProvider.class),
mock(CacheEventDispatcherFactory.class),
mock(CacheEventListenerProvider.class),
mock(LocalPersistenceService.class)));
}
@Test
public void testCanDestroyAndClose() throws Exception {
CacheConfiguration<Long, String> cacheConfiguration = new BaseCacheConfiguration<Long, String>(Long.class, String.class, null,
null, null, ResourcePoolsHelper.createHeapOnlyPools(10));
Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
Store store = mock(Store.class);
CacheEventDispatcherFactory cacheEventNotificationListenerServiceProvider = mock(CacheEventDispatcherFactory.class);
when(storeProvider.createStore(any(Store.Configuration.class), Matchers.<ServiceConfiguration>anyVararg())).thenReturn(store);
when(store.getConfigurationChangeListeners()).thenReturn(new ArrayList<CacheConfigurationChangeListener>());
when(cacheEventNotificationListenerServiceProvider.createCacheEventDispatcher(store)).thenReturn(mock(CacheEventDispatcher.class));
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("aCache", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
PersistentCacheManager cacheManager = new EhcacheManager(config, Arrays.asList(
storeProvider,
mock(CacheLoaderWriterProvider.class),
mock(WriteBehindProvider.class),
cacheEventNotificationListenerServiceProvider,
mock(CacheEventListenerProvider.class),
mock(LocalPersistenceService.class)));
cacheManager.init();
cacheManager.close();
cacheManager.init();
cacheManager.close();
cacheManager.destroy();
cacheManager.init();
cacheManager.close();
}
@Test
public void testConstructionThrowsWhenNotBeingToResolveService() {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
final DefaultConfiguration config = new DefaultConfiguration(caches, null, new ServiceCreationConfiguration<NoSuchService>() {
@Override
public Class<NoSuchService> getServiceType() {
return NoSuchService.class;
}
});
try {
new EhcacheManager(config);
fail("Should have thrown...");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString(NoSuchService.class.getName()));
}
}
@Test
public void testCreationFailsOnDuplicateServiceCreationConfiguration() {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
DefaultConfiguration config = new DefaultConfiguration(caches, null, new ServiceCreationConfiguration<NoSuchService>() {
@Override
public Class<NoSuchService> getServiceType() {
return NoSuchService.class;
}
}, new ServiceCreationConfiguration<NoSuchService>() {
@Override
public Class<NoSuchService> getServiceType() {
return NoSuchService.class;
}
});
try {
new EhcacheManager(config);
fail("Should have thrown ...");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("NoSuchService"));
}
}
@Test
public void testStopAllServicesWhenCacheInitializationFails() {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("myCache", mock(CacheConfiguration.class));
DefaultConfiguration config = new DefaultConfiguration(caches, null);
List<Service> services = minimunCacheManagerServices();
EhcacheManager cacheManager = new EhcacheManager(config, services);
Store.Provider storeProvider = (Store.Provider) services.get(0); // because I know it's the first of the list
try {
cacheManager.init();
fail("Should have thrown...");
} catch (StateTransitionException ste) {
verify(storeProvider).stop();
}
}
@Test
public void testNoClassLoaderSpecified() {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("foo", new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools()));
DefaultConfiguration config = new DefaultConfiguration(caches, null);
final Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
final Store mock = mock(Store.class);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(mock)).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(storeProvider, cenlProvider);
when(storeProvider
.createStore(Matchers.<Store.Configuration>anyObject(), Matchers.<ServiceConfiguration[]>anyVararg())).thenReturn(mock);
EhcacheManager cacheManager = new EhcacheManager(config, services);
cacheManager.init();
assertSame(ClassLoading.getDefaultClassLoader(), cacheManager.getClassLoader());
assertSame(cacheManager.getClassLoader(), cacheManager.getCache("foo", Object.class, Object.class).getRuntimeConfiguration().getClassLoader());
}
@Test
public void testClassLoaderSpecified() {
ClassLoader cl1 = new ClassLoader() {
//
};
ClassLoader cl2 = new ClassLoader() {
//
};
assertNotSame(cl1, cl2);
assertNotSame(cl1.getClass(), cl2.getClass());
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("foo1", new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools()));
caches.put("foo2", new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools()));
caches.put("foo3", new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, cl2, null, ResourcePoolsHelper.createHeapOnlyPools()));
DefaultConfiguration config = new DefaultConfiguration(caches, cl1);
final Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
final Store mock = mock(Store.class);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(mock)).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(storeProvider, cenlProvider);
when(storeProvider
.createStore(Matchers.<Store.Configuration>anyObject(), Matchers.<ServiceConfiguration[]>anyVararg())).thenReturn(mock);
EhcacheManager cacheManager = new EhcacheManager(config, services);
cacheManager.init();
assertSame(cl1, cacheManager.getClassLoader());
assertSame(cl1, cacheManager.getCache("foo1", Object.class, Object.class)
.getRuntimeConfiguration()
.getClassLoader());
assertSame(cl1, cacheManager.getCache("foo2", Object.class, Object.class).getRuntimeConfiguration().getClassLoader());
assertSame(cl2, cacheManager.getCache("foo3", Object.class, Object.class).getRuntimeConfiguration().getClassLoader());
}
@Test
public void testReturnsNullForNonExistCache() {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, getServices(null, null));
cacheManager.init();
assertThat(cacheManager.getCache("foo", Object.class, Object.class), nullValue());
}
@Test
public void testThrowsWhenAddingExistingCache() {
CacheConfiguration<Object, Object> cacheConfiguration = new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
final Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
final Store mock = mock(Store.class);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(mock)).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(storeProvider, cenlProvider);
when(storeProvider
.createStore(Matchers.<Store.Configuration>anyObject(), Matchers.<ServiceConfiguration[]>anyVararg())).thenReturn(mock);
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("bar", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, services);
cacheManager.init();
final Cache<Object, Object> cache = cacheManager.getCache("bar", Object.class, Object.class);
assertNotNull(cache);
try {
cacheManager.createCache("bar", cacheConfiguration);
fail("Should have thrown");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("bar"));
}
}
@Test
public void testThrowsWhenNotInitialized() {
final Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
final Store mock = mock(Store.class);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(mock)).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(storeProvider, cenlProvider);
when(storeProvider
.createStore(Matchers.<Store.Configuration>anyObject(), Matchers.<ServiceConfiguration[]>anyVararg())).thenReturn(mock);
final CacheConfiguration<Integer, String> cacheConfiguration = new BaseCacheConfiguration<Integer, String>(Integer.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("bar", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, services);
try {
cacheManager.removeCache("foo");
fail();
} catch (IllegalStateException e) {
assertThat(e.getMessage().contains(Status.UNINITIALIZED.name()), is(true));
}
try {
cacheManager.createCache("foo", (CacheConfiguration) null);
fail();
} catch (IllegalStateException e) {
assertThat(e.getMessage().contains(Status.UNINITIALIZED.name()), is(true));
}
try {
cacheManager.getCache("foo", Object.class, Object.class);
fail();
} catch (IllegalStateException e) {
assertThat(e.getMessage().contains(Status.UNINITIALIZED.name()), is(true));
}
}
@Test
public void testThrowsWhenRetrievingCacheWithWrongTypes() {
final Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
final Store mock = mock(Store.class);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(mock)).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(storeProvider, cenlProvider);
when(storeProvider
.createStore(Matchers.<Store.Configuration>anyObject(), Matchers.<ServiceConfiguration[]>anyVararg())).thenReturn(mock);
final CacheConfiguration<Integer, String> cacheConfiguration = new BaseCacheConfiguration<Integer, String>(Integer.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("bar", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, services);
cacheManager.init();
cacheManager.getCache("bar", Integer.class, String.class);
try {
cacheManager.getCache("bar", Integer.class, Integer.class);
fail("Should have thrown");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("bar"));
assertTrue(e.getMessage().contains("<java.lang.Integer, java.lang.String>"));
assertTrue(e.getMessage().contains("<java.lang.Integer, java.lang.Integer>"));
}
try {
cacheManager.getCache("bar", String.class, String.class);
fail("Should have thrown");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("bar"));
assertTrue(e.getMessage().contains("<java.lang.Integer, java.lang.String>"));
assertTrue(e.getMessage().contains("<java.lang.String, java.lang.String>"));
}
}
@Test
public void testLifeCyclesCacheLoaders() throws Exception {
ResourcePools resourcePools = ResourcePoolsHelper.createHeapOnlyPools(10);
final CacheLoaderWriterProvider cacheLoaderWriterProvider = mock(CacheLoaderWriterProvider.class);
final CacheConfiguration<Long, Long> barConfig = mock(CacheConfiguration.class);
when(barConfig.getClassLoader()).thenReturn(getClass().getClassLoader());
when(barConfig.getResourcePools()).thenReturn(resourcePools);
final CacheConfiguration<Integer, CharSequence> fooConfig = mock(CacheConfiguration.class);
when(fooConfig.getClassLoader()).thenReturn(getClass().getClassLoader());
when(fooConfig.getResourcePools()).thenReturn(resourcePools);
CacheLoaderWriter fooLoaderWriter = mock(CacheLoaderWriter.class);
final WriteBehindProvider decoratorLoaderWriterProvider = mock(WriteBehindProvider.class);
when(cacheLoaderWriterProvider.createCacheLoaderWriter("foo", fooConfig)).thenReturn(fooLoaderWriter);
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("bar", barConfig);
caches.put("foo", fooConfig);
Configuration cfg = new DefaultConfiguration(
caches,
getClass().getClassLoader()
);
Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
Store mock = mock(Store.class);
CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(mock)).thenReturn(cenlServiceMock);
Collection<Service> services = getServices(cacheLoaderWriterProvider, decoratorLoaderWriterProvider, storeProvider, cenlProvider);
when(storeProvider
.createStore(Matchers.<Store.Configuration>anyObject(), Matchers.<ServiceConfiguration[]>anyVararg())).thenReturn(mock);
EhcacheManager manager = new EhcacheManager(cfg, services);
manager.init();
verify(cacheLoaderWriterProvider).createCacheLoaderWriter("bar", barConfig);
verify(cacheLoaderWriterProvider).createCacheLoaderWriter("foo", fooConfig);
manager.removeCache("bar");
verify(cacheLoaderWriterProvider, never()).releaseCacheLoaderWriter((CacheLoaderWriter<?, ?>)Mockito.anyObject());
manager.removeCache("foo");
verify(cacheLoaderWriterProvider).releaseCacheLoaderWriter(fooLoaderWriter);
}
@Test
public void testDoesNotifyAboutCache() {
final CacheConfiguration<Object, Object> cacheConfiguration = new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
final Store.Provider mock = mock(Store.Provider.class);
when(mock.rank(anySet(), anyCollection())).thenReturn(1);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(any(Store.class))).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(mock, cenlProvider);
when(mock.createStore(Matchers.<Store.Configuration>anyObject())).thenReturn(mock(Store.class));
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, services);
final CacheManagerListener listener = mock(CacheManagerListener.class);
cacheManager.registerListener(listener);
cacheManager.init();
final String cacheAlias = "bar";
cacheManager.createCache(cacheAlias, cacheConfiguration);
final Cache<Object, Object> bar = cacheManager.getCache(cacheAlias, Object.class, Object.class);
verify(listener).cacheAdded(cacheAlias, bar);
cacheManager.removeCache(cacheAlias);
verify(listener).cacheRemoved(cacheAlias, bar);
}
@Test
public void testDoesNotNotifyAboutCacheOnInitOrClose() {
final CacheConfiguration<Object, Object> cacheConfiguration = new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
final Store.Provider mock = mock(Store.Provider.class);
when(mock.rank(anySet(), anyCollection())).thenReturn(1);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(any(Store.class))).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(mock, cenlProvider);
when(mock.createStore(Matchers.<Store.Configuration>anyObject())).thenReturn(mock(Store.class));
final String cacheAlias = "bar";
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put(cacheAlias, cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, services);
final CacheManagerListener listener = mock(CacheManagerListener.class);
cacheManager.registerListener(listener);
cacheManager.init();
final Cache<Object, Object> bar = cacheManager.getCache(cacheAlias, Object.class, Object.class);
verify(listener, never()).cacheAdded(cacheAlias, bar);
cacheManager.close();
verify(listener, never()).cacheRemoved(cacheAlias, bar);
}
@Test
public void testClosesStartedCachesDownWhenInitThrows() {
final Set<Cache<?,?>> caches = new HashSet<Cache<?, ?>>();
final CacheConfiguration<Object, Object> cacheConfiguration = new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
final Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
final Collection<Service> services = getServices(storeProvider, null);
final RuntimeException thrown = new RuntimeException();
when(storeProvider.createStore(Matchers.<Store.Configuration>anyObject())).thenReturn(mock(Store.class));
Map<String, CacheConfiguration<?, ?>> cacheMap = newCacheMap();
cacheMap.put("foo", cacheConfiguration);
cacheMap.put("bar", cacheConfiguration);
cacheMap.put("foobar", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(cacheMap, null);
EhcacheManager cacheManager = new EhcacheManager(config, services) {
@Override
<K, V> InternalCache<K, V> createNewEhcache(final String alias, final CacheConfiguration<K, V> config,
final Class<K> keyType, final Class<V> valueType) {
final InternalCache<K, V> ehcache = super.createNewEhcache(alias, config, keyType, valueType);
caches.add(ehcache);
if(caches.size() == 1) {
when(storeProvider.createStore(Matchers.<Store.Configuration<K,V>>anyObject(),
Matchers.<ServiceConfiguration<?>>anyVararg()))
.thenThrow(thrown);
}
return ehcache;
}
@Override
protected void closeEhcache(final String alias, final InternalCache<?, ?> ehcache) {
super.closeEhcache(alias, ehcache);
caches.remove(ehcache);
}
};
try {
cacheManager.init();
fail();
} catch (StateTransitionException e) {
assertThat(cacheManager.getStatus(), is(Status.UNINITIALIZED));
final String message = e.getCause().getMessage();
assertThat(message, CoreMatchers.startsWith("Cache '"));
assertThat(message, containsString("' creation in "));
assertThat(message, CoreMatchers.endsWith(" failed."));
}
assertThat(caches.isEmpty(), is(true));
}
@Test
public void testClosesAllCachesDownWhenCloseThrows() {
final Set<String> caches = new HashSet<String>();
final CacheConfiguration<Object, Object> cacheConfiguration = new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
final Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
final CacheEventDispatcherFactory cenlProvider = mock(CacheEventDispatcherFactory.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(any(Store.class))).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(storeProvider, cenlProvider);
final RuntimeException thrown = new RuntimeException();
when(storeProvider.createStore(Matchers.<Store.Configuration>anyObject())).thenReturn(mock(Store.class));
Map<String, CacheConfiguration<?, ?>> cacheMap = newCacheMap();
cacheMap.put("foo", cacheConfiguration);
cacheMap.put("bar", cacheConfiguration);
cacheMap.put("foobar", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(cacheMap, null);
EhcacheManager cacheManager = new EhcacheManager(config, services) {
@Override
<K, V> InternalCache<K, V> createNewEhcache(final String alias, final CacheConfiguration<K, V> config,
final Class<K> keyType, final Class<V> valueType) {
final InternalCache<K, V> ehcache = super.createNewEhcache(alias, config, keyType, valueType);
caches.add(alias);
return ehcache;
}
@Override
protected void closeEhcache(final String alias, final InternalCache<?, ?> ehcache) {
super.closeEhcache(alias, ehcache);
if(alias.equals("foobar")) {
throw thrown;
}
caches.remove(alias);
}
};
cacheManager.init();
try {
cacheManager.close();
fail();
} catch (StateTransitionException e) {
assertThat(cacheManager.getStatus(), is(Status.UNINITIALIZED));
assertThat(e.getCause(), CoreMatchers.<Throwable>sameInstance(thrown));
}
assertThat(caches.contains("foobar"), is(true));
}
@Test
public void testDoesNotifyAboutLifecycle() {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, getServices(null, null));
final CacheManagerListener listener = mock(CacheManagerListener.class);
cacheManager.registerListener(listener);
cacheManager.init();
verify(listener).stateTransition(Status.UNINITIALIZED, Status.AVAILABLE);
cacheManager.close();
verify(listener).stateTransition(Status.AVAILABLE, Status.UNINITIALIZED);
}
@Test
public void testCloseNoLoaderWriterAndCacheEventListener() throws Exception {
final CacheConfiguration<Object, Object> cacheConfiguration = new BaseCacheConfiguration<Object, Object>(Object.class, Object.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
final Store.Provider storeProvider = spy(new Store.Provider() {
@Override
public int rank(final Set<ResourceType<?>> resourceTypes, final Collection<ServiceConfiguration<?>> serviceConfigs) {
return 1;
}
@Override
public void stop() {
}
@Override
public void start(ServiceProvider<Service> serviceProvider) {
}
@Override
public void releaseStore(Store<?, ?> resource) {
}
@Override
public void initStore(Store<?, ?> resource) {
}
@Override
public <K, V> Store<K, V> createStore(Store.Configuration<K, V> storeConfig, ServiceConfiguration<?>... serviceConfigs) {
return null;
}
});
final CacheEventDispatcherFactory cenlProvider = spy(new CacheEventDispatcherFactory() {
@Override
public void start(ServiceProvider<Service> serviceProvider) {
}
@Override
public void stop() {
}
@Override
public <K, V> CacheEventDispatcher<K, V> createCacheEventDispatcher(Store<K, V> store, ServiceConfiguration<?>... serviceConfigs) {
return null;
}
@Override
public <K, V> void releaseCacheEventDispatcher(CacheEventDispatcher<K, V> eventDispatcher) {
eventDispatcher.shutdown();
}
});
Store mockStore = mock(Store.class);
final CacheEventDispatcher<Object, Object> cenlServiceMock = mock(CacheEventDispatcher.class);
when(cenlProvider.createCacheEventDispatcher(mockStore)).thenReturn(cenlServiceMock);
final Collection<Service> services = getServices(storeProvider, cenlProvider);
List<CacheConfigurationChangeListener> configurationChangeListenerList = new ArrayList<CacheConfigurationChangeListener>();
configurationChangeListenerList.add(mock(CacheConfigurationChangeListener.class));
when(mockStore.getConfigurationChangeListeners()).thenReturn(configurationChangeListenerList);
when(storeProvider.createStore(Matchers.<Store.Configuration>anyObject())).thenReturn(mockStore);
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("foo", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
EhcacheManager cacheManager = new EhcacheManager(config, services) {
@Override
<K, V> InternalCache<K, V> createNewEhcache(final String alias, final CacheConfiguration<K, V> config, final Class<K> keyType, final Class<V> valueType) {
final InternalCache<K, V> ehcache = super.createNewEhcache(alias, config, keyType, valueType);
return spy(ehcache);
}
};
cacheManager.init();
Cache<Object, Object> testCache = cacheManager.getCache("foo", Object.class, Object.class);
cacheManager.close();
verify((UserManagedCache)testCache).close();
verify(cenlServiceMock, times(1)).shutdown();
}
@Test
public void testChangesToManagerAreReflectedInConfig() {
Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
Store store = mock(Store.class);
CacheEventDispatcherFactory cacheEventNotificationListenerServiceProvider = mock(CacheEventDispatcherFactory.class);
when(storeProvider.createStore(any(Store.Configuration.class), Matchers.<ServiceConfiguration>anyVararg())).thenReturn(store);
when(store.getConfigurationChangeListeners()).thenReturn(new ArrayList<CacheConfigurationChangeListener>());
when(cacheEventNotificationListenerServiceProvider.createCacheEventDispatcher(store)).thenReturn(mock(CacheEventDispatcher.class));
CacheConfiguration<Long, String> cache1Configuration = new BaseCacheConfiguration<Long, String>(Long.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("cache1", cache1Configuration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
CacheManager cacheManager = new EhcacheManager(config, Arrays.asList(storeProvider,
mock(CacheLoaderWriterProvider.class),
mock(WriteBehindProvider.class),
cacheEventNotificationListenerServiceProvider,
mock(CacheEventListenerProvider.class),
mock(LocalPersistenceService.class)
));
cacheManager.init();
try {
final CacheConfiguration<Long, String> cache2Configuration = new BaseCacheConfiguration<Long, String>(Long.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
final Cache<Long, String> cache = cacheManager.createCache("cache2", cache2Configuration);
final CacheConfiguration<?, ?> cacheConfiguration = cacheManager.getRuntimeConfiguration()
.getCacheConfigurations()
.get("cache2");
assertThat(cacheConfiguration, notNullValue());
final CacheConfiguration<?, ?> runtimeConfiguration = cache.getRuntimeConfiguration();
assertThat(cacheConfiguration == runtimeConfiguration, is(true));
assertThat(cacheManager.getRuntimeConfiguration().getCacheConfigurations().get("cache1")
== cacheManager.getCache("cache1", Long.class, String.class).getRuntimeConfiguration(), is(true));
cacheManager.removeCache("cache1");
assertThat(cacheManager.getRuntimeConfiguration().getCacheConfigurations().containsKey("cache1"), is(false));
} finally {
cacheManager.close();
}
}
@Test
public void testCachesAddedAtRuntimeGetReInited() {
Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
Store store = mock(Store.class);
CacheEventDispatcherFactory cacheEventNotificationListenerServiceProvider = mock(CacheEventDispatcherFactory.class);
when(storeProvider.createStore(any(Store.Configuration.class), Matchers.<ServiceConfiguration>anyVararg())).thenReturn(store);
when(store.getConfigurationChangeListeners()).thenReturn(new ArrayList<CacheConfigurationChangeListener>());
when(cacheEventNotificationListenerServiceProvider.createCacheEventDispatcher(store)).thenReturn(mock(CacheEventDispatcher.class));
CacheConfiguration<Long, String> cache1Configuration = new BaseCacheConfiguration<Long, String>(Long.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("cache1", cache1Configuration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
CacheManager cacheManager = new EhcacheManager(config, Arrays.asList(
storeProvider,
mock(CacheLoaderWriterProvider.class),
mock(WriteBehindProvider.class),
cacheEventNotificationListenerServiceProvider,
mock(CacheEventListenerProvider.class),
mock(LocalPersistenceService.class)
));
cacheManager.init();
CacheConfiguration<Long, String> cache2Configuration = new BaseCacheConfiguration<Long, String>(Long.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
cacheManager.createCache("cache2", cache2Configuration);
cacheManager.removeCache("cache1");
cacheManager.close();
cacheManager.init();
try {
assertThat(cacheManager.getCache("cache1", Long.class, String.class), nullValue());
assertThat(cacheManager.getCache("cache2", Long.class, String.class), notNullValue());
} finally {
cacheManager.close();
}
}
@Test
public void testCloseWhenRuntimeCacheCreationFails() throws Exception {
Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
doThrow(new Error("Test EhcacheManager close.")).when(storeProvider).createStore(any(Store.Configuration.class), Matchers.<ServiceConfiguration>anyVararg());
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
DefaultConfiguration config = new DefaultConfiguration(caches, null);
final CacheManager cacheManager = new EhcacheManager(config, Arrays.asList(
storeProvider,
mock(CacheLoaderWriterProvider.class),
mock(WriteBehindProvider.class),
mock(CacheEventDispatcherFactory.class),
mock(CacheEventListenerProvider.class),
mock(LocalPersistenceService.class)
));
cacheManager.init();
CacheConfiguration<Long, String> cacheConfiguration = new BaseCacheConfiguration<Long, String>(Long.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
try {
cacheManager.createCache("cache", cacheConfiguration);
fail();
} catch (Error err) {
assertThat(err.getMessage(), equalTo("Test EhcacheManager close."));
}
cacheManager.close();
assertThat(cacheManager.getStatus(), is(Status.UNINITIALIZED));
}
@Test(timeout = 2000L)
public void testCloseWhenCacheCreationFailsDuringInitialization() throws Exception {
Store.Provider storeProvider = mock(Store.Provider.class);
when(storeProvider.rank(anySet(), anyCollection())).thenReturn(1);
doThrow(new Error("Test EhcacheManager close.")).when(storeProvider).createStore(any(Store.Configuration.class), Matchers.<ServiceConfiguration>anyVararg());
CacheConfiguration<Long, String> cacheConfiguration = new BaseCacheConfiguration<Long, String>(Long.class, String.class, null, null, null, ResourcePoolsHelper.createHeapOnlyPools());
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
caches.put("cache1", cacheConfiguration);
DefaultConfiguration config = new DefaultConfiguration(caches, null);
final CacheManager cacheManager = new EhcacheManager(config, Arrays.asList(
storeProvider,
mock(CacheLoaderWriterProvider.class),
mock(WriteBehindProvider.class),
mock(CacheEventDispatcherFactory.class),
mock(CacheEventListenerProvider.class),
mock(LocalPersistenceService.class)
));
final CountDownLatch countDownLatch = new CountDownLatch(1);
Executors.newSingleThreadExecutor().submit(new Runnable() {
@Override
public void run() {
try {
cacheManager.init();
} catch (Error err) {
assertThat(err.getMessage(), equalTo("Test EhcacheManager close."));
countDownLatch.countDown();
}
}
});
countDownLatch.await();
try {
cacheManager.close();
} catch (IllegalStateException e) {
assertThat(e.getMessage(), is("Close not supported from UNINITIALIZED"));
}
assertThat(cacheManager.getStatus(), is(Status.UNINITIALIZED));
}
@Test
public void testDestroyCacheFailsIfAlreadyInMaintenanceMode() throws CachePersistenceException, InterruptedException {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
DefaultConfiguration config = new DefaultConfiguration(caches, null);
final EhcacheManager manager = new EhcacheManager(config, minimunCacheManagerServices());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
manager.getStatusTransitioner().maintenance().succeeded();
}
});
thread.start();
thread.join(1000);
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("State is MAINTENANCE, yet you don't own it!");
manager.destroyCache("test");
}
@Test
public void testDestroyCacheFailsAndStopIfStartingServicesFails() throws CachePersistenceException, InterruptedException {
Map<String, CacheConfiguration<?, ?>> caches = newCacheMap();
DefaultConfiguration config = new DefaultConfiguration(caches, null);
List<Service> services = minimunCacheManagerServices();
MaintainableService service = mock(MaintainableService.class);
doThrow(new RuntimeException("failed")).when(service)
.startForMaintenance(Mockito.<ServiceProvider<MaintainableService>>anyObject(), eq(MaintainableService.MaintenanceScope.CACHE));
services.add(service);
EhcacheManager manager = new EhcacheManager(config, services);
expectedException.expect(StateTransitionException.class);
expectedException.expectMessage("failed");
manager.destroyCache("test");
assertThat(manager.getStatus(), equalTo(Status.UNINITIALIZED));
}
private Collection<Service> getServices(Store.Provider storeProvider, CacheEventDispatcherFactory cenlProvider) {
return getServices(mock(CacheLoaderWriterProvider.class), mock(WriteBehindProvider.class),
storeProvider != null ? storeProvider : mock(Store.Provider.class),
cenlProvider != null ? cenlProvider : mock(CacheEventDispatcherFactory.class));
}
private Collection<Service> getServices(CacheLoaderWriterProvider cacheLoaderWriterProvider,
WriteBehindProvider decoratorLoaderWriterProvider,
Store.Provider storeProvider,
CacheEventDispatcherFactory cenlProvider) {
return new ArrayList<Service>(Arrays.asList(cacheLoaderWriterProvider, storeProvider, decoratorLoaderWriterProvider, cenlProvider, mock(CacheEventListenerProvider.class)));
}
static class NoSuchService implements Service {
@Override
public void start(final ServiceProvider<Service> serviceProvider) {
throw new UnsupportedOperationException("Implement me!");
}
@Override
public void stop() {
throw new UnsupportedOperationException("Implement me!");
}
}
}